From a54e3130ca1c895f8c3757e3bb1a9a85f659ccfd Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 27 Jul 2024 18:10:56 -0400 Subject: [PATCH 1/6] alphabetize the config fields --- clippy_config/Cargo.toml | 1 + clippy_config/src/conf.rs | 568 +++++++++++++++++++------------------- clippy_config/src/lib.rs | 2 +- 3 files changed, 292 insertions(+), 279 deletions(-) diff --git a/clippy_config/Cargo.toml b/clippy_config/Cargo.toml index e1b2edc8a6ff..c98469e4cbb2 100644 --- a/clippy_config/Cargo.toml +++ b/clippy_config/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +itertools = "0.12" rustc-semver = "1.1" serde = { version = "1.0", features = ["derive"] } toml = "0.7.3" diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 63140a36875d..7d75bdd1b62a 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -218,10 +218,151 @@ macro_rules! define_Conf { sorted.sort_by(|a, b| a.name.cmp(&b.name)); sorted } + + #[test] + pub fn is_conf_ordered() { + use itertools::Itertools; + + let misordered: Vec<_> = [$(stringify!($name),)*].array_windows::<2>().filter(|[x, y]| x > y).collect(); + assert!( + misordered.is_empty(), + "the following config fields are misordered:\n {}", + misordered.iter().format_with("\n ", |[x, y], f| f(&format_args!("{x}, {y}"))), + ); + } }; } define_Conf! { + /// Lint: ABSOLUTE_PATHS. + /// + /// Which crates to allow absolute paths from + (absolute_paths_allowed_crates: FxHashSet = FxHashSet::default()), + /// Lint: ABSOLUTE_PATHS. + /// + /// The maximum number of segments a path can have before being linted, anything above this will + /// be linted. + (absolute_paths_max_segments: u64 = 2), + /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. + /// + /// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block + (accept_comment_above_attributes: bool = true), + /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. + /// + /// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block + (accept_comment_above_statement: bool = true), + /// Lint: MODULO_ARITHMETIC. + /// + /// Don't lint when comparing the result of a modulo operation to zero. + (allow_comparison_to_zero: bool = true), + /// Lint: DBG_MACRO. + /// + /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` + (allow_dbg_in_tests: bool = false), + /// Lint: EXPECT_USED. + /// + /// Whether `expect` should be allowed in test functions or `#[cfg(test)]` + (allow_expect_in_tests: bool = false), + /// Lint: UNINLINED_FORMAT_ARGS. + /// + /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` + (allow_mixed_uninlined_format_args: bool = true), + /// Lint: UNNECESSARY_RAW_STRING_HASHES. + /// + /// Whether to allow `r#""#` when `r""` can be used + (allow_one_hash_in_raw_strings: bool = false), + /// Lint: PANIC. + /// + /// Whether `panic` should be allowed in test functions or `#[cfg(test)]` + (allow_panic_in_tests: bool = false), + /// Lint: PRINT_STDOUT, PRINT_STDERR. + /// + /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` + (allow_print_in_tests: bool = false), + /// Lint: MODULE_INCEPTION. + /// + /// Whether to allow module inception if it's not public. + (allow_private_module_inception: bool = false), + /// Lint: RENAMED_FUNCTION_PARAMS. + /// + /// List of trait paths to ignore when checking renamed function parameters. + /// + /// #### Example + /// + /// ```toml + /// allow-renamed-params-for = [ "std::convert::From" ] + /// ``` + /// + /// #### Noteworthy + /// + /// - By default, the following traits are ignored: `From`, `TryFrom`, `FromStr` + /// - `".."` can be used as part of the list to indicate that the configured values should be appended to the + /// default configuration of Clippy. By default, any configuration will replace the default value. + (allow_renamed_params_for: Vec = + DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS.iter().map(ToString::to_string).collect()), + /// Lint: UNWRAP_USED. + /// + /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` + (allow_unwrap_in_tests: bool = false), + /// Lint: USELESS_VEC. + /// + /// Whether `useless_vec` should ignore test functions or `#[cfg(test)]` + (allow_useless_vec_in_tests: bool = false), + /// Lint: PATH_ENDS_WITH_EXT. + /// + /// Additional dotfiles (files or directories starting with a dot) to allow + (allowed_dotfiles: Vec = Vec::default()), + /// Lint: MULTIPLE_CRATE_VERSIONS. + /// + /// A list of crate names to allow duplicates of + (allowed_duplicate_crates: FxHashSet = FxHashSet::default()), + /// Lint: MIN_IDENT_CHARS. + /// + /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of + /// the list to indicate, that the configured values should be appended to the default + /// configuration of Clippy. By default, any configuration will replace the default value. + (allowed_idents_below_min_chars: FxHashSet = + DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()), + /// Lint: MODULE_NAME_REPETITIONS. + /// + /// List of prefixes to allow when determining whether an item's name ends with the module's name. + /// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`), + /// then don't emit a warning. + /// + /// #### Example + /// + /// ```toml + /// allowed-prefixes = [ "to", "from" ] + /// ``` + /// + /// #### Noteworthy + /// + /// - By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from` + /// - PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included, + /// `TryInto` will also be included) + /// - Use `".."` as part of the list to indicate that the configured values should be appended to the + /// default configuration of Clippy. By default, any configuration will replace the default value + (allowed_prefixes: Vec = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect()), + /// Lint: DISALLOWED_SCRIPT_IDENTS. + /// + /// The list of unicode scripts allowed to be used in the scope. + (allowed_scripts: Vec = vec!["Latin".to_string()]), + /// Lint: WILDCARD_IMPORTS. + /// + /// List of path segments allowed to have wildcard imports. + /// + /// #### Example + /// + /// ```toml + /// allowed-wildcard-imports = [ "utils", "common" ] + /// ``` + /// + /// #### Noteworthy + /// + /// 1. This configuration has no effects if used with `warn_on_all_wildcard_imports = true`. + /// 2. Paths with any segment that containing the word 'prelude' + /// are already allowed by default. + (allowed_wildcard_imports: FxHashSet = FxHashSet::default()), /// Lint: ARITHMETIC_SIDE_EFFECTS. /// /// Suppress checking of the passed type names in all types of operations. @@ -266,47 +407,56 @@ define_Conf! { /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] /// ``` (arithmetic_side_effects_allowed_unary: Vec = <_>::default()), + /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. + /// + /// The maximum allowed size for arrays on the stack + (array_size_threshold: u64 = 512_000), /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NEEDLESS_PASS_BY_REF_MUT. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON, COLLAPSIBLE_MATCH. - /// - /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` - #[default_text = ""] - (msrv: Msrv = Msrv::empty()), + /// Lint: AWAIT_HOLDING_INVALID_TYPE. + (await_holding_invalid_types: Vec = Vec::new()), /// DEPRECATED LINT: BLACKLISTED_NAME. /// /// Use the Disallowed Names lint instead #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)] (blacklisted_names: Vec = Vec::new()), + /// Lint: CARGO_COMMON_METADATA. + /// + /// For internal testing only, ignores the current `publish` settings in the Cargo manifest. + (cargo_ignore_publish: bool = false), + /// Lint: MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC, MISSING_PANICS_DOC, MISSING_ERRORS_DOC. + /// + /// Whether to also run the listed lints on private items. + (check_private_items: bool = false), /// Lint: COGNITIVE_COMPLEXITY. /// /// The maximum cognitive complexity a function can have (cognitive_complexity_threshold: u64 = 25), - /// Lint: EXCESSIVE_NESTING. - /// - /// The maximum amount of nesting a block can reside in - (excessive_nesting_threshold: u64 = 0), /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. /// /// Use the Cognitive Complexity lint instead. #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] (cyclomatic_complexity_threshold: u64 = 25), + /// Lint: DISALLOWED_MACROS. + /// + /// The list of disallowed macros, written as fully qualified paths. + (disallowed_macros: Vec = Vec::new()), + /// Lint: DISALLOWED_METHODS. + /// + /// The list of disallowed methods, written as fully qualified paths. + (disallowed_methods: Vec = Vec::new()), /// Lint: DISALLOWED_NAMES. /// /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value /// `".."` can be used as part of the list to indicate that the configured values should be appended to the /// default configuration of Clippy. By default, any configuration will replace the default value. (disallowed_names: Vec = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), - /// Lint: SEMICOLON_INSIDE_BLOCK. - /// - /// Whether to lint only if it's multiline. - (semicolon_inside_block_ignore_singleline: bool = false), - /// Lint: SEMICOLON_OUTSIDE_BLOCK. + /// Lint: DISALLOWED_TYPES. /// - /// Whether to lint only if it's singleline. - (semicolon_outside_block_ignore_multiline: bool = false), + /// The list of disallowed types, written as fully qualified paths. + (disallowed_types: Vec = Vec::new()), /// Lint: DOC_MARKDOWN. /// /// The list of words this lint should not consider as identifiers needing ticks. The value @@ -315,113 +465,128 @@ define_Conf! { /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. (doc_valid_idents: FxHashSet = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), - /// Lint: TOO_MANY_ARGUMENTS. + /// Lint: NON_SEND_FIELDS_IN_SEND_TY. /// - /// The maximum number of argument a function or method can have - (too_many_arguments_threshold: u64 = 7), - /// Lint: TYPE_COMPLEXITY. + /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. + (enable_raw_pointer_heuristic_for_send: bool = true), + /// Lint: EXPLICIT_ITER_LOOP. /// - /// The maximum complexity a type can have - (type_complexity_threshold: u64 = 250), - /// Lint: MANY_SINGLE_CHAR_NAMES. + /// Whether to recommend using implicit into iter for reborrowed values. /// - /// The maximum number of single char bindings a scope may have - (single_char_binding_names_threshold: u64 = 4), - /// Lint: BOXED_LOCAL, USELESS_VEC. + /// #### Example + /// ```no_run + /// let mut vec = vec![1, 2, 3]; + /// let rmvec = &mut vec; + /// for _ in rmvec.iter() {} + /// for _ in rmvec.iter_mut() {} + /// ``` /// - /// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap - (too_large_for_stack: u64 = 200), + /// Use instead: + /// ```no_run + /// let mut vec = vec![1, 2, 3]; + /// let rmvec = &mut vec; + /// for _ in &*rmvec {} + /// for _ in &mut *rmvec {} + /// ``` + (enforce_iter_loop_reborrow: bool = false), + /// Lint: MISSING_ENFORCED_IMPORT_RENAMES. + /// + /// The list of imports to always rename, a fully qualified path followed by the rename. + (enforced_import_renames: Vec = Vec::new()), /// Lint: ENUM_VARIANT_NAMES. /// /// The minimum number of enum variants for the lints about variant names to trigger (enum_variant_name_threshold: u64 = 3), - /// Lint: STRUCT_FIELD_NAMES. - /// - /// The minimum number of struct fields for the lints about field names to trigger - (struct_field_name_threshold: u64 = 3), /// Lint: LARGE_ENUM_VARIANT. /// /// The maximum size of an enum's variant to avoid box suggestion (enum_variant_size_threshold: u64 = 200), - /// Lint: VERBOSE_BIT_MASK. + /// Lint: EXCESSIVE_NESTING. /// - /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' - (verbose_bit_mask_threshold: u64 = 1), + /// The maximum amount of nesting a block can reside in + (excessive_nesting_threshold: u64 = 0), + /// Lint: LARGE_FUTURES. + /// + /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint + (future_size_threshold: u64 = 16 * 1024), + /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND, BORROW_INTERIOR_MUTABLE_CONST, DECLARE_INTERIOR_MUTABLE_CONST. + /// + /// A list of paths to types that should be treated as if they do not contain interior mutability + (ignore_interior_mutability: Vec = Vec::from(["bytes::Bytes".into()])), + /// Lint: RESULT_LARGE_ERR. + /// + /// The maximum size of the `Err`-variant in a `Result` returned from a function + (large_error_threshold: u64 = 128), /// Lint: DECIMAL_LITERAL_REPRESENTATION. /// /// The lower bound for linting decimal literals (literal_representation_threshold: u64 = 16384), - /// Lint: TRIVIALLY_COPY_PASS_BY_REF. + /// Lint: MANUAL_LET_ELSE. /// - /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by - /// reference. By default there is no limit - #[default_text = ""] - (trivial_copy_size_limit: Option = None), - /// Lint: LARGE_TYPES_PASSED_BY_VALUE. + /// Whether the matches should be considered by the lint, and whether there should + /// be filtering for common types. + (matches_for_let_else: MatchLintBehaviour = MatchLintBehaviour::WellKnownTypes), + /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. /// - /// The minimum size (in bytes) to consider a type for passing by reference instead of by value. - (pass_by_value_size_limit: u64 = 256), - /// Lint: TOO_MANY_LINES. + /// The maximum number of bool parameters a function can have + (max_fn_params_bools: u64 = 3), + /// Lint: LARGE_INCLUDE_FILE. /// - /// The maximum number of lines a function or method can have - (too_many_lines_threshold: u64 = 100), - /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. + /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes + (max_include_file_size: u64 = 1_000_000), + /// Lint: STRUCT_EXCESSIVE_BOOLS. /// - /// The maximum allowed size for arrays on the stack - (array_size_threshold: u64 = 512_000), - /// Lint: LARGE_STACK_FRAMES. - /// - /// The maximum allowed stack size for functions in bytes - (stack_size_threshold: u64 = 512_000), - /// Lint: VEC_BOX. + /// The maximum number of bool fields a struct can have + (max_struct_bools: u64 = 3), + /// Lint: INDEX_REFUTABLE_SLICE. /// - /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed - (vec_box_size_threshold: u64 = 4096), + /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in + /// the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. + /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. + (max_suggested_slice_pattern_length: u64 = 3), /// Lint: TYPE_REPETITION_IN_BOUNDS. /// /// The maximum number of bounds a trait can have to be linted (max_trait_bounds: u64 = 3), - /// Lint: STRUCT_EXCESSIVE_BOOLS. - /// - /// The maximum number of bool fields a struct can have - (max_struct_bools: u64 = 3), - /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. + /// Lint: MIN_IDENT_CHARS. /// - /// The maximum number of bool parameters a function can have - (max_fn_params_bools: u64 = 3), - /// Lint: WILDCARD_IMPORTS. + /// Minimum chars an ident can have, anything below or equal to this will be linted. + (min_ident_chars_threshold: u64 = 1), + /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS. /// - /// Whether to allow certain wildcard imports (prelude, super in tests). - (warn_on_all_wildcard_imports: bool = false), - /// Lint: DISALLOWED_MACROS. + /// Whether to **only** check for missing documentation in items visible within the current + /// crate. For example, `pub(crate)` items. + (missing_docs_in_crate_items: bool = false), + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON, COLLAPSIBLE_MATCH. /// - /// The list of disallowed macros, written as fully qualified paths. - (disallowed_macros: Vec = Vec::new()), - /// Lint: DISALLOWED_METHODS. + /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` + #[default_text = ""] + (msrv: Msrv = Msrv::empty()), + /// Lint: LARGE_TYPES_PASSED_BY_VALUE. /// - /// The list of disallowed methods, written as fully qualified paths. - (disallowed_methods: Vec = Vec::new()), - /// Lint: DISALLOWED_TYPES. + /// The minimum size (in bytes) to consider a type for passing by reference instead of by value. + (pass_by_value_size_limit: u64 = 256), + /// Lint: PUB_UNDERSCORE_FIELDS. /// - /// The list of disallowed types, written as fully qualified paths. - (disallowed_types: Vec = Vec::new()), - /// Lint: UNREADABLE_LITERAL. + /// Lint "public" fields in a struct that are prefixed with an underscore based on their + /// exported visibility, or whether they are marked as "pub". + (pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported), + /// Lint: SEMICOLON_INSIDE_BLOCK. /// - /// Should the fraction of a decimal be linted to include separators. - (unreadable_literal_lint_fractions: bool = true), - /// Lint: UPPER_CASE_ACRONYMS. + /// Whether to lint only if it's multiline. + (semicolon_inside_block_ignore_singleline: bool = false), + /// Lint: SEMICOLON_OUTSIDE_BLOCK. /// - /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other - (upper_case_acronyms_aggressive: bool = false), - /// Lint: MANUAL_LET_ELSE. + /// Whether to lint only if it's singleline. + (semicolon_outside_block_ignore_multiline: bool = false), + /// Lint: MANY_SINGLE_CHAR_NAMES. /// - /// Whether the matches should be considered by the lint, and whether there should - /// be filtering for common types. - (matches_for_let_else: MatchLintBehaviour = MatchLintBehaviour::WellKnownTypes), - /// Lint: CARGO_COMMON_METADATA. + /// The maximum number of single char bindings a scope may have + (single_char_binding_names_threshold: u64 = 4), + /// Lint: LARGE_STACK_FRAMES. /// - /// For internal testing only, ignores the current `publish` settings in the Cargo manifest. - (cargo_ignore_publish: bool = false), + /// The maximum allowed stack size for functions in bytes + (stack_size_threshold: u64 = 512_000), /// Lint: NONSTANDARD_MACRO_BRACES. /// /// Enforce the named macros always use the braces specified. @@ -430,66 +595,10 @@ define_Conf! { /// could be used with a full path two `MacroMatcher`s have to be added one with the full path /// `crate_name::macro_name` and one with just the macro name. (standard_macro_braces: Vec = Vec::new()), - /// Lint: MISSING_ENFORCED_IMPORT_RENAMES. - /// - /// The list of imports to always rename, a fully qualified path followed by the rename. - (enforced_import_renames: Vec = Vec::new()), - /// Lint: DISALLOWED_SCRIPT_IDENTS. - /// - /// The list of unicode scripts allowed to be used in the scope. - (allowed_scripts: Vec = vec!["Latin".to_string()]), - /// Lint: NON_SEND_FIELDS_IN_SEND_TY. - /// - /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. - (enable_raw_pointer_heuristic_for_send: bool = true), - /// Lint: INDEX_REFUTABLE_SLICE. - /// - /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in - /// the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. - /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. - (max_suggested_slice_pattern_length: u64 = 3), - /// Lint: AWAIT_HOLDING_INVALID_TYPE. - (await_holding_invalid_types: Vec = Vec::new()), - /// Lint: LARGE_INCLUDE_FILE. - /// - /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes - (max_include_file_size: u64 = 1_000_000), - /// Lint: EXPECT_USED. - /// - /// Whether `expect` should be allowed in test functions or `#[cfg(test)]` - (allow_expect_in_tests: bool = false), - /// Lint: UNWRAP_USED. - /// - /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` - (allow_unwrap_in_tests: bool = false), - /// Lint: PANIC. - /// - /// Whether `panic` should be allowed in test functions or `#[cfg(test)]` - (allow_panic_in_tests: bool = false), - /// Lint: DBG_MACRO. - /// - /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` - (allow_dbg_in_tests: bool = false), - /// Lint: PRINT_STDOUT, PRINT_STDERR. - /// - /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` - (allow_print_in_tests: bool = false), - /// Lint: USELESS_VEC. - /// - /// Whether `useless_vec` should ignore test functions or `#[cfg(test)]` - (allow_useless_vec_in_tests: bool = false), - /// Lint: RESULT_LARGE_ERR. - /// - /// The maximum size of the `Err`-variant in a `Result` returned from a function - (large_error_threshold: u64 = 128), - /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND, BORROW_INTERIOR_MUTABLE_CONST, DECLARE_INTERIOR_MUTABLE_CONST. - /// - /// A list of paths to types that should be treated as if they do not contain interior mutability - (ignore_interior_mutability: Vec = Vec::from(["bytes::Bytes".into()])), - /// Lint: UNINLINED_FORMAT_ARGS. + /// Lint: STRUCT_FIELD_NAMES. /// - /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` - (allow_mixed_uninlined_format_args: bool = true), + /// The minimum number of struct fields for the lints about field names to trigger + (struct_field_name_threshold: u64 = 3), /// Lint: INDEXING_SLICING. /// /// Whether to suppress a restriction lint in constant code. In same @@ -498,149 +607,52 @@ define_Conf! { /// configuration will cause restriction lints to trigger even /// if no suggestion can be made. (suppress_restriction_lint_in_const: bool = false), - /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS. - /// - /// Whether to **only** check for missing documentation in items visible within the current - /// crate. For example, `pub(crate)` items. - (missing_docs_in_crate_items: bool = false), - /// Lint: LARGE_FUTURES. - /// - /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint - (future_size_threshold: u64 = 16 * 1024), - /// Lint: UNNECESSARY_BOX_RETURNS. - /// - /// The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint - (unnecessary_box_size: u64 = 128), - /// Lint: MODULE_INCEPTION. - /// - /// Whether to allow module inception if it's not public. - (allow_private_module_inception: bool = false), - /// Lint: MIN_IDENT_CHARS. - /// - /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of - /// the list to indicate, that the configured values should be appended to the default - /// configuration of Clippy. By default, any configuration will replace the default value. - (allowed_idents_below_min_chars: FxHashSet = - DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()), - /// Lint: MIN_IDENT_CHARS. - /// - /// Minimum chars an ident can have, anything below or equal to this will be linted. - (min_ident_chars_threshold: u64 = 1), - /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. - /// - /// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block - (accept_comment_above_statement: bool = true), - /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. - /// - /// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block - (accept_comment_above_attributes: bool = true), - /// Lint: UNNECESSARY_RAW_STRING_HASHES. - /// - /// Whether to allow `r#""#` when `r""` can be used - (allow_one_hash_in_raw_strings: bool = false), - /// Lint: ABSOLUTE_PATHS. + /// Lint: BOXED_LOCAL, USELESS_VEC. /// - /// The maximum number of segments a path can have before being linted, anything above this will - /// be linted. - (absolute_paths_max_segments: u64 = 2), - /// Lint: ABSOLUTE_PATHS. + /// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap + (too_large_for_stack: u64 = 200), + /// Lint: TOO_MANY_ARGUMENTS. /// - /// Which crates to allow absolute paths from - (absolute_paths_allowed_crates: FxHashSet = FxHashSet::default()), - /// Lint: PATH_ENDS_WITH_EXT. + /// The maximum number of argument a function or method can have + (too_many_arguments_threshold: u64 = 7), + /// Lint: TOO_MANY_LINES. /// - /// Additional dotfiles (files or directories starting with a dot) to allow - (allowed_dotfiles: Vec = Vec::default()), - /// Lint: MULTIPLE_CRATE_VERSIONS. + /// The maximum number of lines a function or method can have + (too_many_lines_threshold: u64 = 100), + /// Lint: TRIVIALLY_COPY_PASS_BY_REF. /// - /// A list of crate names to allow duplicates of - (allowed_duplicate_crates: FxHashSet = FxHashSet::default()), - /// Lint: EXPLICIT_ITER_LOOP. + /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by + /// reference. By default there is no limit + #[default_text = ""] + (trivial_copy_size_limit: Option = None), + /// Lint: TYPE_COMPLEXITY. /// - /// Whether to recommend using implicit into iter for reborrowed values. + /// The maximum complexity a type can have + (type_complexity_threshold: u64 = 250), + /// Lint: UNNECESSARY_BOX_RETURNS. /// - /// #### Example - /// ```no_run - /// let mut vec = vec![1, 2, 3]; - /// let rmvec = &mut vec; - /// for _ in rmvec.iter() {} - /// for _ in rmvec.iter_mut() {} - /// ``` + /// The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint + (unnecessary_box_size: u64 = 128), + /// Lint: UNREADABLE_LITERAL. /// - /// Use instead: - /// ```no_run - /// let mut vec = vec![1, 2, 3]; - /// let rmvec = &mut vec; - /// for _ in &*rmvec {} - /// for _ in &mut *rmvec {} - /// ``` - (enforce_iter_loop_reborrow: bool = false), - /// Lint: MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC, MISSING_PANICS_DOC, MISSING_ERRORS_DOC. + /// Should the fraction of a decimal be linted to include separators. + (unreadable_literal_lint_fractions: bool = true), + /// Lint: UPPER_CASE_ACRONYMS. /// - /// Whether to also run the listed lints on private items. - (check_private_items: bool = false), - /// Lint: PUB_UNDERSCORE_FIELDS. + /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other + (upper_case_acronyms_aggressive: bool = false), + /// Lint: VEC_BOX. /// - /// Lint "public" fields in a struct that are prefixed with an underscore based on their - /// exported visibility, or whether they are marked as "pub". - (pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported), - /// Lint: MODULO_ARITHMETIC. + /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed + (vec_box_size_threshold: u64 = 4096), + /// Lint: VERBOSE_BIT_MASK. /// - /// Don't lint when comparing the result of a modulo operation to zero. - (allow_comparison_to_zero: bool = true), + /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' + (verbose_bit_mask_threshold: u64 = 1), /// Lint: WILDCARD_IMPORTS. /// - /// List of path segments allowed to have wildcard imports. - /// - /// #### Example - /// - /// ```toml - /// allowed-wildcard-imports = [ "utils", "common" ] - /// ``` - /// - /// #### Noteworthy - /// - /// 1. This configuration has no effects if used with `warn_on_all_wildcard_imports = true`. - /// 2. Paths with any segment that containing the word 'prelude' - /// are already allowed by default. - (allowed_wildcard_imports: FxHashSet = FxHashSet::default()), - /// Lint: MODULE_NAME_REPETITIONS. - /// - /// List of prefixes to allow when determining whether an item's name ends with the module's name. - /// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`), - /// then don't emit a warning. - /// - /// #### Example - /// - /// ```toml - /// allowed-prefixes = [ "to", "from" ] - /// ``` - /// - /// #### Noteworthy - /// - /// - By default, the following prefixes are allowed: `to`, `as`, `into`, `from`, `try_into` and `try_from` - /// - PascalCase variant is included automatically for each snake_case variant (e.g. if `try_into` is included, - /// `TryInto` will also be included) - /// - Use `".."` as part of the list to indicate that the configured values should be appended to the - /// default configuration of Clippy. By default, any configuration will replace the default value - (allowed_prefixes: Vec = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect()), - /// Lint: RENAMED_FUNCTION_PARAMS. - /// - /// List of trait paths to ignore when checking renamed function parameters. - /// - /// #### Example - /// - /// ```toml - /// allow-renamed-params-for = [ "std::convert::From" ] - /// ``` - /// - /// #### Noteworthy - /// - /// - By default, the following traits are ignored: `From`, `TryFrom`, `FromStr` - /// - `".."` can be used as part of the list to indicate that the configured values should be appended to the - /// default configuration of Clippy. By default, any configuration will replace the default value. - (allow_renamed_params_for: Vec = - DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS.iter().map(ToString::to_string).collect()), + /// Whether to allow certain wildcard imports (prelude, super in tests). + (warn_on_all_wildcard_imports: bool = false), /// Lint: MACRO_METAVARS_IN_UNSAFE. /// /// Whether to also emit warnings for unsafe blocks with metavariable expansions in **private** macros. diff --git a/clippy_config/src/lib.rs b/clippy_config/src/lib.rs index ff7fa7241cb9..c099585e62a1 100644 --- a/clippy_config/src/lib.rs +++ b/clippy_config/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, let_chains)] +#![feature(rustc_private, array_windows, let_chains)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn( trivial_casts, From 84dc56923bb24743ae10c737e0022bcc87f222ac Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 27 Jul 2024 18:17:26 -0400 Subject: [PATCH 2/6] Add docs for `await_holding_invalid_types` --- book/src/lint_configuration.md | 2 +- clippy_config/src/conf.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index fb717a2c166d..aaf58956a8b3 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -364,7 +364,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat ## `await-holding-invalid-types` - +The list of types which may not be held across an await point. **Default Value:** `[]` diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 7d75bdd1b62a..2aeca6d0f90c 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -416,6 +416,8 @@ define_Conf! { /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), /// Lint: AWAIT_HOLDING_INVALID_TYPE. + /// + /// The list of types which may not be held across an await point. (await_holding_invalid_types: Vec = Vec::new()), /// DEPRECATED LINT: BLACKLISTED_NAME. /// From 7a25ead416e828f9aa6b3038d5f8478accdc3844 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 27 Jul 2024 19:23:23 -0400 Subject: [PATCH 3/6] Remove unneeded parens in config macro --- clippy_config/src/conf.rs | 160 +++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index 2aeca6d0f90c..f7779b19ea0d 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -123,7 +123,7 @@ macro_rules! define_Conf { $(#[doc = $doc:literal])+ $(#[conf_deprecated($dep:literal, $new_conf:ident)])? $(#[default_text = $default_text:expr])? - ($name:ident: $ty:ty = $default:expr), + $name:ident: $ty:ty = $default:expr, )*) => { /// Clippy lint configuration pub struct Conf { @@ -237,52 +237,52 @@ define_Conf! { /// Lint: ABSOLUTE_PATHS. /// /// Which crates to allow absolute paths from - (absolute_paths_allowed_crates: FxHashSet = FxHashSet::default()), + absolute_paths_allowed_crates: FxHashSet = FxHashSet::default(), /// Lint: ABSOLUTE_PATHS. /// /// The maximum number of segments a path can have before being linted, anything above this will /// be linted. - (absolute_paths_max_segments: u64 = 2), + absolute_paths_max_segments: u64 = 2, /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. /// /// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block - (accept_comment_above_attributes: bool = true), + accept_comment_above_attributes: bool = true, /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. /// /// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block - (accept_comment_above_statement: bool = true), + accept_comment_above_statement: bool = true, /// Lint: MODULO_ARITHMETIC. /// /// Don't lint when comparing the result of a modulo operation to zero. - (allow_comparison_to_zero: bool = true), + allow_comparison_to_zero: bool = true, /// Lint: DBG_MACRO. /// /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` - (allow_dbg_in_tests: bool = false), + allow_dbg_in_tests: bool = false, /// Lint: EXPECT_USED. /// /// Whether `expect` should be allowed in test functions or `#[cfg(test)]` - (allow_expect_in_tests: bool = false), + allow_expect_in_tests: bool = false, /// Lint: UNINLINED_FORMAT_ARGS. /// /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` - (allow_mixed_uninlined_format_args: bool = true), + allow_mixed_uninlined_format_args: bool = true, /// Lint: UNNECESSARY_RAW_STRING_HASHES. /// /// Whether to allow `r#""#` when `r""` can be used - (allow_one_hash_in_raw_strings: bool = false), + allow_one_hash_in_raw_strings: bool = false, /// Lint: PANIC. /// /// Whether `panic` should be allowed in test functions or `#[cfg(test)]` - (allow_panic_in_tests: bool = false), + allow_panic_in_tests: bool = false, /// Lint: PRINT_STDOUT, PRINT_STDERR. /// /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` - (allow_print_in_tests: bool = false), + allow_print_in_tests: bool = false, /// Lint: MODULE_INCEPTION. /// /// Whether to allow module inception if it's not public. - (allow_private_module_inception: bool = false), + allow_private_module_inception: bool = false, /// Lint: RENAMED_FUNCTION_PARAMS. /// /// List of trait paths to ignore when checking renamed function parameters. @@ -298,31 +298,31 @@ define_Conf! { /// - By default, the following traits are ignored: `From`, `TryFrom`, `FromStr` /// - `".."` can be used as part of the list to indicate that the configured values should be appended to the /// default configuration of Clippy. By default, any configuration will replace the default value. - (allow_renamed_params_for: Vec = - DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS.iter().map(ToString::to_string).collect()), + allow_renamed_params_for: Vec = + DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS.iter().map(ToString::to_string).collect(), /// Lint: UNWRAP_USED. /// /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` - (allow_unwrap_in_tests: bool = false), + allow_unwrap_in_tests: bool = false, /// Lint: USELESS_VEC. /// /// Whether `useless_vec` should ignore test functions or `#[cfg(test)]` - (allow_useless_vec_in_tests: bool = false), + allow_useless_vec_in_tests: bool = false, /// Lint: PATH_ENDS_WITH_EXT. /// /// Additional dotfiles (files or directories starting with a dot) to allow - (allowed_dotfiles: Vec = Vec::default()), + allowed_dotfiles: Vec = Vec::default(), /// Lint: MULTIPLE_CRATE_VERSIONS. /// /// A list of crate names to allow duplicates of - (allowed_duplicate_crates: FxHashSet = FxHashSet::default()), + allowed_duplicate_crates: FxHashSet = FxHashSet::default(), /// Lint: MIN_IDENT_CHARS. /// /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of /// the list to indicate, that the configured values should be appended to the default /// configuration of Clippy. By default, any configuration will replace the default value. - (allowed_idents_below_min_chars: FxHashSet = - DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()), + allowed_idents_below_min_chars: FxHashSet = + DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect(), /// Lint: MODULE_NAME_REPETITIONS. /// /// List of prefixes to allow when determining whether an item's name ends with the module's name. @@ -342,11 +342,11 @@ define_Conf! { /// `TryInto` will also be included) /// - Use `".."` as part of the list to indicate that the configured values should be appended to the /// default configuration of Clippy. By default, any configuration will replace the default value - (allowed_prefixes: Vec = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect()), + allowed_prefixes: Vec = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect(), /// Lint: DISALLOWED_SCRIPT_IDENTS. /// /// The list of unicode scripts allowed to be used in the scope. - (allowed_scripts: Vec = vec!["Latin".to_string()]), + allowed_scripts: Vec = vec!["Latin".to_string()], /// Lint: WILDCARD_IMPORTS. /// /// List of path segments allowed to have wildcard imports. @@ -362,7 +362,7 @@ define_Conf! { /// 1. This configuration has no effects if used with `warn_on_all_wildcard_imports = true`. /// 2. Paths with any segment that containing the word 'prelude' /// are already allowed by default. - (allowed_wildcard_imports: FxHashSet = FxHashSet::default()), + allowed_wildcard_imports: FxHashSet = FxHashSet::default(), /// Lint: ARITHMETIC_SIDE_EFFECTS. /// /// Suppress checking of the passed type names in all types of operations. @@ -379,7 +379,7 @@ define_Conf! { /// /// A type, say `SomeType`, listed in this configuration has the same behavior of /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. - (arithmetic_side_effects_allowed: Vec = <_>::default()), + arithmetic_side_effects_allowed: Vec = <_>::default(), /// Lint: ARITHMETIC_SIDE_EFFECTS. /// /// Suppress checking of the passed type pair names in binary operations like addition or @@ -396,7 +396,7 @@ define_Conf! { /// ```toml /// arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]] /// ``` - (arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default()), + arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default(), /// Lint: ARITHMETIC_SIDE_EFFECTS. /// /// Suppress checking of the passed type names in unary operations like "negation" (`-`). @@ -406,59 +406,59 @@ define_Conf! { /// ```toml /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] /// ``` - (arithmetic_side_effects_allowed_unary: Vec = <_>::default()), + arithmetic_side_effects_allowed_unary: Vec = <_>::default(), /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. /// /// The maximum allowed size for arrays on the stack - (array_size_threshold: u64 = 512_000), + array_size_threshold: u64 = 512_000, /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NEEDLESS_PASS_BY_REF_MUT. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. - (avoid_breaking_exported_api: bool = true), + avoid_breaking_exported_api: bool = true, /// Lint: AWAIT_HOLDING_INVALID_TYPE. /// /// The list of types which may not be held across an await point. - (await_holding_invalid_types: Vec = Vec::new()), + await_holding_invalid_types: Vec = Vec::new(), /// DEPRECATED LINT: BLACKLISTED_NAME. /// /// Use the Disallowed Names lint instead #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)] - (blacklisted_names: Vec = Vec::new()), + blacklisted_names: Vec = Vec::new(), /// Lint: CARGO_COMMON_METADATA. /// /// For internal testing only, ignores the current `publish` settings in the Cargo manifest. - (cargo_ignore_publish: bool = false), + cargo_ignore_publish: bool = false, /// Lint: MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC, MISSING_PANICS_DOC, MISSING_ERRORS_DOC. /// /// Whether to also run the listed lints on private items. - (check_private_items: bool = false), + check_private_items: bool = false, /// Lint: COGNITIVE_COMPLEXITY. /// /// The maximum cognitive complexity a function can have - (cognitive_complexity_threshold: u64 = 25), + cognitive_complexity_threshold: u64 = 25, /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. /// /// Use the Cognitive Complexity lint instead. #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] - (cyclomatic_complexity_threshold: u64 = 25), + cyclomatic_complexity_threshold: u64 = 25, /// Lint: DISALLOWED_MACROS. /// /// The list of disallowed macros, written as fully qualified paths. - (disallowed_macros: Vec = Vec::new()), + disallowed_macros: Vec = Vec::new(), /// Lint: DISALLOWED_METHODS. /// /// The list of disallowed methods, written as fully qualified paths. - (disallowed_methods: Vec = Vec::new()), + disallowed_methods: Vec = Vec::new(), /// Lint: DISALLOWED_NAMES. /// /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value /// `".."` can be used as part of the list to indicate that the configured values should be appended to the /// default configuration of Clippy. By default, any configuration will replace the default value. - (disallowed_names: Vec = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), + disallowed_names: Vec = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect(), /// Lint: DISALLOWED_TYPES. /// /// The list of disallowed types, written as fully qualified paths. - (disallowed_types: Vec = Vec::new()), + disallowed_types: Vec = Vec::new(), /// Lint: DOC_MARKDOWN. /// /// The list of words this lint should not consider as identifiers needing ticks. The value @@ -466,11 +466,11 @@ define_Conf! { /// default configuration of Clippy. By default, any configuration will replace the default value. For example: /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. - (doc_valid_idents: FxHashSet = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()), + doc_valid_idents: FxHashSet = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect(), /// Lint: NON_SEND_FIELDS_IN_SEND_TY. /// /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. - (enable_raw_pointer_heuristic_for_send: bool = true), + enable_raw_pointer_heuristic_for_send: bool = true, /// Lint: EXPLICIT_ITER_LOOP. /// /// Whether to recommend using implicit into iter for reborrowed values. @@ -490,105 +490,105 @@ define_Conf! { /// for _ in &*rmvec {} /// for _ in &mut *rmvec {} /// ``` - (enforce_iter_loop_reborrow: bool = false), + enforce_iter_loop_reborrow: bool = false, /// Lint: MISSING_ENFORCED_IMPORT_RENAMES. /// /// The list of imports to always rename, a fully qualified path followed by the rename. - (enforced_import_renames: Vec = Vec::new()), + enforced_import_renames: Vec = Vec::new(), /// Lint: ENUM_VARIANT_NAMES. /// /// The minimum number of enum variants for the lints about variant names to trigger - (enum_variant_name_threshold: u64 = 3), + enum_variant_name_threshold: u64 = 3, /// Lint: LARGE_ENUM_VARIANT. /// /// The maximum size of an enum's variant to avoid box suggestion - (enum_variant_size_threshold: u64 = 200), + enum_variant_size_threshold: u64 = 200, /// Lint: EXCESSIVE_NESTING. /// /// The maximum amount of nesting a block can reside in - (excessive_nesting_threshold: u64 = 0), + excessive_nesting_threshold: u64 = 0, /// Lint: LARGE_FUTURES. /// /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint - (future_size_threshold: u64 = 16 * 1024), + future_size_threshold: u64 = 16 * 1024, /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND, BORROW_INTERIOR_MUTABLE_CONST, DECLARE_INTERIOR_MUTABLE_CONST. /// /// A list of paths to types that should be treated as if they do not contain interior mutability - (ignore_interior_mutability: Vec = Vec::from(["bytes::Bytes".into()])), + ignore_interior_mutability: Vec = Vec::from(["bytes::Bytes".into()]), /// Lint: RESULT_LARGE_ERR. /// /// The maximum size of the `Err`-variant in a `Result` returned from a function - (large_error_threshold: u64 = 128), + large_error_threshold: u64 = 128, /// Lint: DECIMAL_LITERAL_REPRESENTATION. /// /// The lower bound for linting decimal literals - (literal_representation_threshold: u64 = 16384), + literal_representation_threshold: u64 = 16384, /// Lint: MANUAL_LET_ELSE. /// /// Whether the matches should be considered by the lint, and whether there should /// be filtering for common types. - (matches_for_let_else: MatchLintBehaviour = MatchLintBehaviour::WellKnownTypes), + matches_for_let_else: MatchLintBehaviour = MatchLintBehaviour::WellKnownTypes, /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. /// /// The maximum number of bool parameters a function can have - (max_fn_params_bools: u64 = 3), + max_fn_params_bools: u64 = 3, /// Lint: LARGE_INCLUDE_FILE. /// /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes - (max_include_file_size: u64 = 1_000_000), + max_include_file_size: u64 = 1_000_000, /// Lint: STRUCT_EXCESSIVE_BOOLS. /// /// The maximum number of bool fields a struct can have - (max_struct_bools: u64 = 3), + max_struct_bools: u64 = 3, /// Lint: INDEX_REFUTABLE_SLICE. /// /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in /// the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. - (max_suggested_slice_pattern_length: u64 = 3), + max_suggested_slice_pattern_length: u64 = 3, /// Lint: TYPE_REPETITION_IN_BOUNDS. /// /// The maximum number of bounds a trait can have to be linted - (max_trait_bounds: u64 = 3), + max_trait_bounds: u64 = 3, /// Lint: MIN_IDENT_CHARS. /// /// Minimum chars an ident can have, anything below or equal to this will be linted. - (min_ident_chars_threshold: u64 = 1), + min_ident_chars_threshold: u64 = 1, /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS. /// /// Whether to **only** check for missing documentation in items visible within the current /// crate. For example, `pub(crate)` items. - (missing_docs_in_crate_items: bool = false), + missing_docs_in_crate_items: bool = false, /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON, COLLAPSIBLE_MATCH. /// /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` #[default_text = ""] - (msrv: Msrv = Msrv::empty()), + msrv: Msrv = Msrv::empty(), /// Lint: LARGE_TYPES_PASSED_BY_VALUE. /// /// The minimum size (in bytes) to consider a type for passing by reference instead of by value. - (pass_by_value_size_limit: u64 = 256), + pass_by_value_size_limit: u64 = 256, /// Lint: PUB_UNDERSCORE_FIELDS. /// /// Lint "public" fields in a struct that are prefixed with an underscore based on their /// exported visibility, or whether they are marked as "pub". - (pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported), + pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported, /// Lint: SEMICOLON_INSIDE_BLOCK. /// /// Whether to lint only if it's multiline. - (semicolon_inside_block_ignore_singleline: bool = false), + semicolon_inside_block_ignore_singleline: bool = false, /// Lint: SEMICOLON_OUTSIDE_BLOCK. /// /// Whether to lint only if it's singleline. - (semicolon_outside_block_ignore_multiline: bool = false), + semicolon_outside_block_ignore_multiline: bool = false, /// Lint: MANY_SINGLE_CHAR_NAMES. /// /// The maximum number of single char bindings a scope may have - (single_char_binding_names_threshold: u64 = 4), + single_char_binding_names_threshold: u64 = 4, /// Lint: LARGE_STACK_FRAMES. /// /// The maximum allowed stack size for functions in bytes - (stack_size_threshold: u64 = 512_000), + stack_size_threshold: u64 = 512_000, /// Lint: NONSTANDARD_MACRO_BRACES. /// /// Enforce the named macros always use the braces specified. @@ -596,11 +596,11 @@ define_Conf! { /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro /// could be used with a full path two `MacroMatcher`s have to be added one with the full path /// `crate_name::macro_name` and one with just the macro name. - (standard_macro_braces: Vec = Vec::new()), + standard_macro_braces: Vec = Vec::new(), /// Lint: STRUCT_FIELD_NAMES. /// /// The minimum number of struct fields for the lints about field names to trigger - (struct_field_name_threshold: u64 = 3), + struct_field_name_threshold: u64 = 3, /// Lint: INDEXING_SLICING. /// /// Whether to suppress a restriction lint in constant code. In same @@ -608,57 +608,57 @@ define_Conf! { /// suggested counterparts are unavailable in constant code. This /// configuration will cause restriction lints to trigger even /// if no suggestion can be made. - (suppress_restriction_lint_in_const: bool = false), + suppress_restriction_lint_in_const: bool = false, /// Lint: BOXED_LOCAL, USELESS_VEC. /// /// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap - (too_large_for_stack: u64 = 200), + too_large_for_stack: u64 = 200, /// Lint: TOO_MANY_ARGUMENTS. /// /// The maximum number of argument a function or method can have - (too_many_arguments_threshold: u64 = 7), + too_many_arguments_threshold: u64 = 7, /// Lint: TOO_MANY_LINES. /// /// The maximum number of lines a function or method can have - (too_many_lines_threshold: u64 = 100), + too_many_lines_threshold: u64 = 100, /// Lint: TRIVIALLY_COPY_PASS_BY_REF. /// /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by /// reference. By default there is no limit #[default_text = ""] - (trivial_copy_size_limit: Option = None), + trivial_copy_size_limit: Option = None, /// Lint: TYPE_COMPLEXITY. /// /// The maximum complexity a type can have - (type_complexity_threshold: u64 = 250), + type_complexity_threshold: u64 = 250, /// Lint: UNNECESSARY_BOX_RETURNS. /// /// The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint - (unnecessary_box_size: u64 = 128), + unnecessary_box_size: u64 = 128, /// Lint: UNREADABLE_LITERAL. /// /// Should the fraction of a decimal be linted to include separators. - (unreadable_literal_lint_fractions: bool = true), + unreadable_literal_lint_fractions: bool = true, /// Lint: UPPER_CASE_ACRONYMS. /// /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other - (upper_case_acronyms_aggressive: bool = false), + upper_case_acronyms_aggressive: bool = false, /// Lint: VEC_BOX. /// /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed - (vec_box_size_threshold: u64 = 4096), + vec_box_size_threshold: u64 = 4096, /// Lint: VERBOSE_BIT_MASK. /// /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' - (verbose_bit_mask_threshold: u64 = 1), + verbose_bit_mask_threshold: u64 = 1, /// Lint: WILDCARD_IMPORTS. /// /// Whether to allow certain wildcard imports (prelude, super in tests). - (warn_on_all_wildcard_imports: bool = false), + warn_on_all_wildcard_imports: bool = false, /// Lint: MACRO_METAVARS_IN_UNSAFE. /// /// Whether to also emit warnings for unsafe blocks with metavariable expansions in **private** macros. - (warn_unsafe_macro_metavars_in_private_macros: bool = false), + warn_unsafe_macro_metavars_in_private_macros: bool = false, } /// Search for the configuration file. From 7422202ca5c2edfd8f7855eb323f4168a08fba55 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 27 Jul 2024 23:34:16 -0400 Subject: [PATCH 4/6] Add missing default values --- book/src/lint_configuration.md | 4 ++++ clippy_config/src/conf.rs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index aaf58956a8b3..e3d550b14662 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -668,6 +668,8 @@ crate. For example, `pub(crate)` items. ## `msrv` The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` +**Default Value:** `current version` + --- **Affected lints:** * [`allow_attributes`](https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes) @@ -862,6 +864,8 @@ The maximum number of lines a function or method can have The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference. By default there is no limit +**Default Value:** `target_pointer_width * 2` + --- **Affected lints:** * [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index f7779b19ea0d..d13e198ce433 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -562,7 +562,7 @@ define_Conf! { /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON, COLLAPSIBLE_MATCH. /// /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` - #[default_text = ""] + #[default_text = "current version"] msrv: Msrv = Msrv::empty(), /// Lint: LARGE_TYPES_PASSED_BY_VALUE. /// @@ -625,7 +625,7 @@ define_Conf! { /// /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by /// reference. By default there is no limit - #[default_text = ""] + #[default_text = "target_pointer_width * 2"] trivial_copy_size_limit: Option = None, /// Lint: TYPE_COMPLEXITY. /// From 1d06ad55999b29b658f0a885bd8fb0a3be0282fd Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 27 Jul 2024 23:35:54 -0400 Subject: [PATCH 5/6] Mark the lints for each config via an attribute instead of a doc comment.. --- clippy_config/src/conf.rs | 338 +++++++++--------- clippy_config/src/metadata.rs | 103 +----- clippy_lints/src/lib.rs | 2 +- .../internal_lints/metadata_collector.rs | 2 +- 4 files changed, 173 insertions(+), 272 deletions(-) diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs index d13e198ce433..4c2a8255d6b6 100644 --- a/clippy_config/src/conf.rs +++ b/clippy_config/src/conf.rs @@ -123,6 +123,7 @@ macro_rules! define_Conf { $(#[doc = $doc:literal])+ $(#[conf_deprecated($dep:literal, $new_conf:ident)])? $(#[default_text = $default_text:expr])? + $(#[lints($($for_lints:ident),* $(,)?)])? $name:ident: $ty:ty = $default:expr, )*) => { /// Clippy lint configuration @@ -201,90 +202,57 @@ macro_rules! define_Conf { } pub fn get_configuration_metadata() -> Vec { - let mut sorted = vec![ - $( - { - let deprecation_reason = wrap_option!($($dep)?); - - ClippyConfiguration::new( - stringify!($name), - default_text!(defaults::$name() $(, $default_text)?), - concat!($($doc, '\n',)*), - deprecation_reason, - ) - }, - )+ - ]; - sorted.sort_by(|a, b| a.name.cmp(&b.name)); - sorted - } - - #[test] - pub fn is_conf_ordered() { - use itertools::Itertools; - - let misordered: Vec<_> = [$(stringify!($name),)*].array_windows::<2>().filter(|[x, y]| x > y).collect(); - assert!( - misordered.is_empty(), - "the following config fields are misordered:\n {}", - misordered.iter().format_with("\n ", |[x, y], f| f(&format_args!("{x}, {y}"))), - ); + vec![$( + ClippyConfiguration { + name: stringify!($name).replace('_', "-"), + default: default_text!(defaults::$name() $(, $default_text)?), + lints: &[$($(stringify!($for_lints)),*)?], + doc: concat!($($doc, '\n',)*), + deprecation_reason: wrap_option!($($dep)?) + }, + )*] } }; } define_Conf! { - /// Lint: ABSOLUTE_PATHS. - /// /// Which crates to allow absolute paths from + #[lints(absolute_paths)] absolute_paths_allowed_crates: FxHashSet = FxHashSet::default(), - /// Lint: ABSOLUTE_PATHS. - /// /// The maximum number of segments a path can have before being linted, anything above this will /// be linted. + #[lints(absolute_paths)] absolute_paths_max_segments: u64 = 2, - /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. - /// /// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block + #[lints(undocumented_unsafe_blocks)] accept_comment_above_attributes: bool = true, - /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. - /// /// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block + #[lints(undocumented_unsafe_blocks)] accept_comment_above_statement: bool = true, - /// Lint: MODULO_ARITHMETIC. - /// /// Don't lint when comparing the result of a modulo operation to zero. + #[lints(modulo_arithmetic)] allow_comparison_to_zero: bool = true, - /// Lint: DBG_MACRO. - /// /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` + #[lints(dbg_macro)] allow_dbg_in_tests: bool = false, - /// Lint: EXPECT_USED. - /// /// Whether `expect` should be allowed in test functions or `#[cfg(test)]` + #[lints(expect_used)] allow_expect_in_tests: bool = false, - /// Lint: UNINLINED_FORMAT_ARGS. - /// /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` + #[lints(uninlined_format_args)] allow_mixed_uninlined_format_args: bool = true, - /// Lint: UNNECESSARY_RAW_STRING_HASHES. - /// /// Whether to allow `r#""#` when `r""` can be used + #[lints(unnecessary_raw_string_hashes)] allow_one_hash_in_raw_strings: bool = false, - /// Lint: PANIC. - /// /// Whether `panic` should be allowed in test functions or `#[cfg(test)]` + #[lints(panic)] allow_panic_in_tests: bool = false, - /// Lint: PRINT_STDOUT, PRINT_STDERR. - /// /// Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` + #[lints(print_stderr, print_stdout)] allow_print_in_tests: bool = false, - /// Lint: MODULE_INCEPTION. - /// /// Whether to allow module inception if it's not public. + #[lints(module_inception)] allow_private_module_inception: bool = false, - /// Lint: RENAMED_FUNCTION_PARAMS. - /// /// List of trait paths to ignore when checking renamed function parameters. /// /// #### Example @@ -298,33 +266,27 @@ define_Conf! { /// - By default, the following traits are ignored: `From`, `TryFrom`, `FromStr` /// - `".."` can be used as part of the list to indicate that the configured values should be appended to the /// default configuration of Clippy. By default, any configuration will replace the default value. + #[lints(renamed_function_params)] allow_renamed_params_for: Vec = DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS.iter().map(ToString::to_string).collect(), - /// Lint: UNWRAP_USED. - /// /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` + #[lints(unwrap_used)] allow_unwrap_in_tests: bool = false, - /// Lint: USELESS_VEC. - /// /// Whether `useless_vec` should ignore test functions or `#[cfg(test)]` + #[lints(useless_vec)] allow_useless_vec_in_tests: bool = false, - /// Lint: PATH_ENDS_WITH_EXT. - /// /// Additional dotfiles (files or directories starting with a dot) to allow + #[lints(path_ends_with_ext)] allowed_dotfiles: Vec = Vec::default(), - /// Lint: MULTIPLE_CRATE_VERSIONS. - /// /// A list of crate names to allow duplicates of + #[lints(multiple_crate_versions)] allowed_duplicate_crates: FxHashSet = FxHashSet::default(), - /// Lint: MIN_IDENT_CHARS. - /// /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of /// the list to indicate, that the configured values should be appended to the default /// configuration of Clippy. By default, any configuration will replace the default value. + #[lints(min_ident_chars)] allowed_idents_below_min_chars: FxHashSet = DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect(), - /// Lint: MODULE_NAME_REPETITIONS. - /// /// List of prefixes to allow when determining whether an item's name ends with the module's name. /// If the rest of an item's name is an allowed prefix (e.g. item `ToFoo` or `to_foo` in module `foo`), /// then don't emit a warning. @@ -342,13 +304,11 @@ define_Conf! { /// `TryInto` will also be included) /// - Use `".."` as part of the list to indicate that the configured values should be appended to the /// default configuration of Clippy. By default, any configuration will replace the default value + #[lints(module_name_repetitions)] allowed_prefixes: Vec = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect(), - /// Lint: DISALLOWED_SCRIPT_IDENTS. - /// /// The list of unicode scripts allowed to be used in the scope. + #[lints(disallowed_script_idents)] allowed_scripts: Vec = vec!["Latin".to_string()], - /// Lint: WILDCARD_IMPORTS. - /// /// List of path segments allowed to have wildcard imports. /// /// #### Example @@ -362,9 +322,8 @@ define_Conf! { /// 1. This configuration has no effects if used with `warn_on_all_wildcard_imports = true`. /// 2. Paths with any segment that containing the word 'prelude' /// are already allowed by default. + #[lints(wildcard_imports)] allowed_wildcard_imports: FxHashSet = FxHashSet::default(), - /// Lint: ARITHMETIC_SIDE_EFFECTS. - /// /// Suppress checking of the passed type names in all types of operations. /// /// If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead. @@ -379,9 +338,8 @@ define_Conf! { /// /// A type, say `SomeType`, listed in this configuration has the same behavior of /// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`. + #[lints(arithmetic_side_effects)] arithmetic_side_effects_allowed: Vec = <_>::default(), - /// Lint: ARITHMETIC_SIDE_EFFECTS. - /// /// Suppress checking of the passed type pair names in binary operations like addition or /// multiplication. /// @@ -396,9 +354,8 @@ define_Conf! { /// ```toml /// arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]] /// ``` + #[lints(arithmetic_side_effects)] arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default(), - /// Lint: ARITHMETIC_SIDE_EFFECTS. - /// /// Suppress checking of the passed type names in unary operations like "negation" (`-`). /// /// #### Example @@ -406,73 +363,78 @@ define_Conf! { /// ```toml /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] /// ``` + #[lints(arithmetic_side_effects)] arithmetic_side_effects_allowed_unary: Vec = <_>::default(), - /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. - /// /// The maximum allowed size for arrays on the stack + #[lints(large_const_arrays, large_stack_arrays)] array_size_threshold: u64 = 512_000, - /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN, NEEDLESS_PASS_BY_REF_MUT. - /// /// Suppress lints whenever the suggested change would cause breakage for other crates. + #[lints( + box_collection, + enum_variant_names, + large_types_passed_by_value, + linkedlist, + needless_pass_by_ref_mut, + option_option, + rc_buffer, + rc_mutex, + redundant_allocation, + single_call_fn, + trivially_copy_pass_by_ref, + unnecessary_box_returns, + unnecessary_wraps, + unused_self, + upper_case_acronyms, + vec_box, + wrong_self_convention, + )] avoid_breaking_exported_api: bool = true, - /// Lint: AWAIT_HOLDING_INVALID_TYPE. - /// /// The list of types which may not be held across an await point. + #[lints(await_holding_invalid_type)] await_holding_invalid_types: Vec = Vec::new(), /// DEPRECATED LINT: BLACKLISTED_NAME. /// /// Use the Disallowed Names lint instead #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)] blacklisted_names: Vec = Vec::new(), - /// Lint: CARGO_COMMON_METADATA. - /// /// For internal testing only, ignores the current `publish` settings in the Cargo manifest. + #[lints(cargo_common_metadata)] cargo_ignore_publish: bool = false, - /// Lint: MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC, MISSING_PANICS_DOC, MISSING_ERRORS_DOC. - /// /// Whether to also run the listed lints on private items. + #[lints(missing_errors_doc, missing_panics_doc, missing_safety_doc, unnecessary_safety_doc)] check_private_items: bool = false, - /// Lint: COGNITIVE_COMPLEXITY. - /// /// The maximum cognitive complexity a function can have + #[lints(cognitive_complexity)] cognitive_complexity_threshold: u64 = 25, /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. /// /// Use the Cognitive Complexity lint instead. #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] cyclomatic_complexity_threshold: u64 = 25, - /// Lint: DISALLOWED_MACROS. - /// /// The list of disallowed macros, written as fully qualified paths. + #[lints(disallowed_macros)] disallowed_macros: Vec = Vec::new(), - /// Lint: DISALLOWED_METHODS. - /// /// The list of disallowed methods, written as fully qualified paths. + #[lints(disallowed_methods)] disallowed_methods: Vec = Vec::new(), - /// Lint: DISALLOWED_NAMES. - /// /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value /// `".."` can be used as part of the list to indicate that the configured values should be appended to the /// default configuration of Clippy. By default, any configuration will replace the default value. + #[lints(disallowed_names)] disallowed_names: Vec = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect(), - /// Lint: DISALLOWED_TYPES. - /// /// The list of disallowed types, written as fully qualified paths. + #[lints(disallowed_types)] disallowed_types: Vec = Vec::new(), - /// Lint: DOC_MARKDOWN. - /// /// The list of words this lint should not consider as identifiers needing ticks. The value /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the /// default configuration of Clippy. By default, any configuration will replace the default value. For example: /// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. /// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. + #[lints(doc_markdown)] doc_valid_idents: FxHashSet = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect(), - /// Lint: NON_SEND_FIELDS_IN_SEND_TY. - /// /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. + #[lints(non_send_fields_in_send_ty)] enable_raw_pointer_heuristic_for_send: bool = true, - /// Lint: EXPLICIT_ITER_LOOP. - /// /// Whether to recommend using implicit into iter for reborrowed values. /// /// #### Example @@ -490,174 +452,194 @@ define_Conf! { /// for _ in &*rmvec {} /// for _ in &mut *rmvec {} /// ``` + #[lints(explicit_iter_loop)] enforce_iter_loop_reborrow: bool = false, - /// Lint: MISSING_ENFORCED_IMPORT_RENAMES. - /// /// The list of imports to always rename, a fully qualified path followed by the rename. + #[lints(missing_enforced_import_renames)] enforced_import_renames: Vec = Vec::new(), - /// Lint: ENUM_VARIANT_NAMES. - /// /// The minimum number of enum variants for the lints about variant names to trigger + #[lints(enum_variant_names)] enum_variant_name_threshold: u64 = 3, - /// Lint: LARGE_ENUM_VARIANT. - /// /// The maximum size of an enum's variant to avoid box suggestion + #[lints(large_enum_variant)] enum_variant_size_threshold: u64 = 200, - /// Lint: EXCESSIVE_NESTING. - /// /// The maximum amount of nesting a block can reside in + #[lints(excessive_nesting)] excessive_nesting_threshold: u64 = 0, - /// Lint: LARGE_FUTURES. - /// /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint + #[lints(large_futures)] future_size_threshold: u64 = 16 * 1024, - /// Lint: MUTABLE_KEY_TYPE, IFS_SAME_COND, BORROW_INTERIOR_MUTABLE_CONST, DECLARE_INTERIOR_MUTABLE_CONST. - /// /// A list of paths to types that should be treated as if they do not contain interior mutability + #[lints(borrow_interior_mutable_const, declare_interior_mutable_const, ifs_same_cond, mutable_key_type)] ignore_interior_mutability: Vec = Vec::from(["bytes::Bytes".into()]), - /// Lint: RESULT_LARGE_ERR. - /// /// The maximum size of the `Err`-variant in a `Result` returned from a function + #[lints(result_large_err)] large_error_threshold: u64 = 128, - /// Lint: DECIMAL_LITERAL_REPRESENTATION. - /// /// The lower bound for linting decimal literals + #[lints(decimal_literal_representation)] literal_representation_threshold: u64 = 16384, - /// Lint: MANUAL_LET_ELSE. - /// /// Whether the matches should be considered by the lint, and whether there should /// be filtering for common types. + #[lints(manual_let_else)] matches_for_let_else: MatchLintBehaviour = MatchLintBehaviour::WellKnownTypes, - /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. - /// /// The maximum number of bool parameters a function can have + #[lints(fn_params_excessive_bools)] max_fn_params_bools: u64 = 3, - /// Lint: LARGE_INCLUDE_FILE. - /// /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes + #[lints(large_include_file)] max_include_file_size: u64 = 1_000_000, - /// Lint: STRUCT_EXCESSIVE_BOOLS. - /// /// The maximum number of bool fields a struct can have + #[lints(struct_excessive_bools)] max_struct_bools: u64 = 3, - /// Lint: INDEX_REFUTABLE_SLICE. - /// /// When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in /// the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. + #[lints(index_refutable_slice)] max_suggested_slice_pattern_length: u64 = 3, - /// Lint: TYPE_REPETITION_IN_BOUNDS. - /// /// The maximum number of bounds a trait can have to be linted + #[lints(type_repetition_in_bounds)] max_trait_bounds: u64 = 3, - /// Lint: MIN_IDENT_CHARS. - /// /// Minimum chars an ident can have, anything below or equal to this will be linted. + #[lints(min_ident_chars)] min_ident_chars_threshold: u64 = 1, - /// Lint: MISSING_DOCS_IN_PRIVATE_ITEMS. - /// /// Whether to **only** check for missing documentation in items visible within the current /// crate. For example, `pub(crate)` items. + #[lints(missing_docs_in_private_items)] missing_docs_in_crate_items: bool = false, - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES, LEGACY_NUMERIC_CONSTANTS, MANUAL_PATTERN_CHAR_COMPARISON, ALLOW_ATTRIBUTES, ALLOW_ATTRIBUTES_WITHOUT_REASON, COLLAPSIBLE_MATCH. - /// /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml` #[default_text = "current version"] + #[lints( + allow_attributes, + allow_attributes_without_reason, + almost_complete_range, + approx_constant, + assigning_clones, + borrow_as_ptr, + cast_abs_to_unsigned, + checked_conversions, + cloned_instead_of_copied, + collapsible_match, + collapsible_str_replace, + deprecated_cfg_attr, + derivable_impls, + err_expect, + filter_map_next, + from_over_into, + if_then_some_else_none, + index_refutable_slice, + iter_kv_map, + legacy_numeric_constants, + manual_bits, + manual_c_str_literals, + manual_clamp, + manual_hash_one, + manual_is_ascii_check, + manual_let_else, + manual_non_exhaustive, + manual_pattern_char_comparison, + manual_range_contains, + manual_rem_euclid, + manual_retain, + manual_split_once, + manual_str_repeat, + manual_strip, + manual_try_fold, + map_clone, + map_unwrap_or, + match_like_matches_macro, + mem_replace_with_default, + missing_const_for_fn, + needless_borrow, + option_as_ref_deref, + option_map_unwrap_or, + ptr_as_ptr, + redundant_field_names, + redundant_static_lifetimes, + seek_from_current, + seek_rewind, + transmute_ptr_to_ref, + tuple_array_conversions, + type_repetition_in_bounds, + unchecked_duration_subtraction, + uninlined_format_args, + unnecessary_lazy_evaluations, + unnested_or_patterns, + use_self, + )] msrv: Msrv = Msrv::empty(), - /// Lint: LARGE_TYPES_PASSED_BY_VALUE. - /// /// The minimum size (in bytes) to consider a type for passing by reference instead of by value. + #[lints(large_types_passed_by_value)] pass_by_value_size_limit: u64 = 256, - /// Lint: PUB_UNDERSCORE_FIELDS. - /// /// Lint "public" fields in a struct that are prefixed with an underscore based on their /// exported visibility, or whether they are marked as "pub". + #[lints(pub_underscore_fields)] pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported, - /// Lint: SEMICOLON_INSIDE_BLOCK. - /// /// Whether to lint only if it's multiline. + #[lints(semicolon_inside_block)] semicolon_inside_block_ignore_singleline: bool = false, - /// Lint: SEMICOLON_OUTSIDE_BLOCK. - /// /// Whether to lint only if it's singleline. + #[lints(semicolon_outside_block)] semicolon_outside_block_ignore_multiline: bool = false, - /// Lint: MANY_SINGLE_CHAR_NAMES. - /// /// The maximum number of single char bindings a scope may have + #[lints(many_single_char_names)] single_char_binding_names_threshold: u64 = 4, - /// Lint: LARGE_STACK_FRAMES. - /// /// The maximum allowed stack size for functions in bytes + #[lints(large_stack_frames)] stack_size_threshold: u64 = 512_000, - /// Lint: NONSTANDARD_MACRO_BRACES. - /// /// Enforce the named macros always use the braces specified. /// /// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro /// could be used with a full path two `MacroMatcher`s have to be added one with the full path /// `crate_name::macro_name` and one with just the macro name. + #[lints(nonstandard_macro_braces)] standard_macro_braces: Vec = Vec::new(), - /// Lint: STRUCT_FIELD_NAMES. - /// /// The minimum number of struct fields for the lints about field names to trigger + #[lints(struct_field_names)] struct_field_name_threshold: u64 = 3, - /// Lint: INDEXING_SLICING. - /// /// Whether to suppress a restriction lint in constant code. In same /// cases the restructured operation might not be unavoidable, as the /// suggested counterparts are unavailable in constant code. This /// configuration will cause restriction lints to trigger even /// if no suggestion can be made. + #[lints(indexing_slicing)] suppress_restriction_lint_in_const: bool = false, - /// Lint: BOXED_LOCAL, USELESS_VEC. - /// /// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap + #[lints(boxed_local, useless_vec)] too_large_for_stack: u64 = 200, - /// Lint: TOO_MANY_ARGUMENTS. - /// /// The maximum number of argument a function or method can have + #[lints(too_many_arguments)] too_many_arguments_threshold: u64 = 7, - /// Lint: TOO_MANY_LINES. - /// /// The maximum number of lines a function or method can have + #[lints(too_many_lines)] too_many_lines_threshold: u64 = 100, - /// Lint: TRIVIALLY_COPY_PASS_BY_REF. - /// /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by /// reference. By default there is no limit #[default_text = "target_pointer_width * 2"] + #[lints(trivially_copy_pass_by_ref)] trivial_copy_size_limit: Option = None, - /// Lint: TYPE_COMPLEXITY. - /// /// The maximum complexity a type can have + #[lints(type_complexity)] type_complexity_threshold: u64 = 250, - /// Lint: UNNECESSARY_BOX_RETURNS. - /// /// The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint + #[lints(unnecessary_box_returns)] unnecessary_box_size: u64 = 128, - /// Lint: UNREADABLE_LITERAL. - /// /// Should the fraction of a decimal be linted to include separators. + #[lints(unreadable_literal)] unreadable_literal_lint_fractions: bool = true, - /// Lint: UPPER_CASE_ACRONYMS. - /// /// Enables verbose mode. Triggers if there is more than one uppercase char next to each other + #[lints(upper_case_acronyms)] upper_case_acronyms_aggressive: bool = false, - /// Lint: VEC_BOX. - /// /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed + #[lints(vec_box)] vec_box_size_threshold: u64 = 4096, - /// Lint: VERBOSE_BIT_MASK. - /// /// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' + #[lints(verbose_bit_mask)] verbose_bit_mask_threshold: u64 = 1, - /// Lint: WILDCARD_IMPORTS. - /// /// Whether to allow certain wildcard imports (prelude, super in tests). + #[lints(wildcard_imports)] warn_on_all_wildcard_imports: bool = false, - /// Lint: MACRO_METAVARS_IN_UNSAFE. - /// /// Whether to also emit warnings for unsafe blocks with metavariable expansions in **private** macros. + #[lints(macro_metavars_in_unsafe)] warn_unsafe_macro_metavars_in_private_macros: bool = false, } diff --git a/clippy_config/src/metadata.rs b/clippy_config/src/metadata.rs index 400887185e8c..e05bc1a60bf4 100644 --- a/clippy_config/src/metadata.rs +++ b/clippy_config/src/metadata.rs @@ -1,11 +1,12 @@ -use std::fmt::{self, Write}; +use itertools::Itertools; +use std::fmt; #[derive(Debug, Clone, Default)] pub struct ClippyConfiguration { pub name: String, pub default: String, - pub lints: Vec, - pub doc: String, + pub lints: &'static [&'static str], + pub doc: &'static str, pub deprecation_reason: Option<&'static str>, } @@ -20,54 +21,16 @@ impl fmt::Display for ClippyConfiguration { } impl ClippyConfiguration { - pub fn new( - name: &'static str, - default: String, - doc_comment: &'static str, - deprecation_reason: Option<&'static str>, - ) -> Self { - let (mut lints, doc) = parse_config_field_doc(doc_comment) - .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string())); - - lints.sort(); - - Self { - name: to_kebab(name), - lints, - doc, - default, - deprecation_reason, - } - } - pub fn to_markdown_paragraph(&self) -> String { - let mut out = format!( - "## `{}`\n{}\n\n", + format!( + "## `{}`\n{}\n\n**Default Value:** `{}`\n\n---\n**Affected lints:**\n{}\n\n", self.name, - self.doc - .lines() - .map(|line| line.strip_prefix(" ").unwrap_or(line)) - .collect::>() - .join("\n"), - ); - - if !self.default.is_empty() { - write!(out, "**Default Value:** `{}`\n\n", self.default).unwrap(); - } - - write!( - out, - "---\n**Affected lints:**\n{}\n\n", - self.lints - .iter() - .map(|name| name.to_string().split_whitespace().next().unwrap().to_string()) - .map(|name| format!("* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})")) - .collect::>() - .join("\n"), + self.doc.lines().map(|x| x.strip_prefix(' ').unwrap_or(x)).join("\n"), + self.default, + self.lints.iter().format_with("\n", |name, f| f(&format_args!( + "* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})" + ))), ) - .unwrap(); - - out } pub fn to_markdown_link(&self) -> String { @@ -75,47 +38,3 @@ impl ClippyConfiguration { format!("[`{}`]: {BOOK_CONFIGS_PATH}#{}", self.name, self.name) } } - -/// This parses the field documentation of the config struct. -/// -/// ```rust, ignore -/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin") -/// ``` -/// -/// Would yield: -/// ```rust, ignore -/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin") -/// ``` -fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec, String)> { - const DOC_START: &str = " Lint: "; - if doc_comment.starts_with(DOC_START) - && let Some(split_pos) = doc_comment.find('.') - { - let mut doc_comment = doc_comment.to_string(); - let mut documentation = doc_comment.split_off(split_pos); - - // Extract lints - doc_comment.make_ascii_lowercase(); - let lints: Vec = doc_comment - .split_off(DOC_START.len()) - .lines() - .next() - .unwrap() - .split(", ") - .map(str::to_string) - .collect(); - - // Format documentation correctly - // split off leading `.` from lint name list and indent for correct formatting - documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n "); - - Some((lints, documentation)) - } else { - None - } -} - -/// Transforms a given `snake_case_string` to a tasty `kebab-case-string` -fn to_kebab(config_name: &str) -> String { - config_name.replace('_', "-") -} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9c035bfca39c..0ca66063ef21 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -496,7 +496,7 @@ pub fn explain(name: &str) -> i32 { // Check if the lint has configuration let mut mdconf = get_configuration_metadata(); let name = name.to_ascii_lowercase(); - mdconf.retain(|cconf| cconf.lints.contains(&name)); + mdconf.retain(|cconf| cconf.lints.contains(&&*name)); if !mdconf.is_empty() { println!("### Configuration for {}:\n", info.lint.name_lower()); for conf in mdconf { diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 1c149f204562..7fec2e384964 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -165,7 +165,7 @@ impl MetadataCollector { fn get_lint_configs(&self, lint_name: &str) -> Option { self.config .iter() - .filter(|config| config.lints.iter().any(|lint| lint == lint_name)) + .filter(|config| config.lints.iter().any(|&lint| lint == lint_name)) .map(ToString::to_string) .reduce(|acc, x| acc + &x) .map(|configurations| { From 78a750e8904bbb75656c05eda18afef27c77a276 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 28 Jul 2024 00:42:28 -0400 Subject: [PATCH 6/6] Sort the config list using `dev fmt` --- clippy_dev/src/fmt.rs | 392 +++++++++++++++++++++++++++++++----------- 1 file changed, 291 insertions(+), 101 deletions(-) diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 256231441817..5fc4365c6e78 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -1,30 +1,65 @@ use crate::clippy_project_root; use itertools::Itertools; +use rustc_lexer::{tokenize, TokenKind}; use shell_escape::escape; use std::ffi::{OsStr, OsString}; -use std::path::Path; +use std::ops::ControlFlow; +use std::path::{Path, PathBuf}; use std::process::{self, Command, Stdio}; use std::{fs, io}; use walkdir::WalkDir; -#[derive(Debug)] -pub enum CliError { +pub enum Error { CommandFailed(String, String), - IoError(io::Error), + Io(io::Error), RustfmtNotInstalled, - WalkDirError(walkdir::Error), + WalkDir(walkdir::Error), IntellijSetupActive, + Parse(PathBuf, usize, String), + CheckFailed, } -impl From for CliError { +impl From for Error { fn from(error: io::Error) -> Self { - Self::IoError(error) + Self::Io(error) } } -impl From for CliError { +impl From for Error { fn from(error: walkdir::Error) -> Self { - Self::WalkDirError(error) + Self::WalkDir(error) + } +} + +impl Error { + fn display(&self) { + match self { + Self::CheckFailed => { + eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update."); + }, + Self::CommandFailed(command, stderr) => { + eprintln!("error: command `{command}` failed!\nstderr: {stderr}"); + }, + Self::Io(err) => { + eprintln!("error: {err}"); + }, + Self::RustfmtNotInstalled => { + eprintln!("error: rustfmt nightly is not installed."); + }, + Self::WalkDir(err) => { + eprintln!("error: {err}"); + }, + Self::IntellijSetupActive => { + eprintln!( + "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`.\n\ + Not formatting because that would format the local repo as well!\n\ + Please revert the changes to `Cargo.toml`s with `cargo dev remove intellij`." + ); + }, + Self::Parse(path, line, msg) => { + eprintln!("error parsing `{}:{line}`: {msg}", path.display()); + }, + } } } @@ -34,75 +69,244 @@ struct FmtContext { rustfmt_path: String, } -// the "main" function of cargo dev fmt -pub fn run(check: bool, verbose: bool) { - fn try_run(context: &FmtContext) -> Result { - let mut success = true; - - let project_root = clippy_project_root(); - - // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to - // format because rustfmt would also format the entire rustc repo as it is a local - // dependency - if fs::read_to_string(project_root.join("Cargo.toml")) - .expect("Failed to read clippy Cargo.toml") - .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]") - { - return Err(CliError::IntellijSetupActive); - } - - rustfmt_test(context)?; +struct ClippyConf<'a> { + name: &'a str, + attrs: &'a str, + lints: Vec<&'a str>, + field: &'a str, +} - success &= cargo_fmt(context, project_root.as_path())?; - success &= cargo_fmt(context, &project_root.join("clippy_dev"))?; - success &= cargo_fmt(context, &project_root.join("rustc_tools_util"))?; - success &= cargo_fmt(context, &project_root.join("lintcheck"))?; +fn offset_to_line(text: &str, offset: usize) -> usize { + match text.split('\n').try_fold((1usize, 0usize), |(line, pos), s| { + let pos = pos + s.len() + 1; + if pos > offset { + ControlFlow::Break(line) + } else { + ControlFlow::Continue((line + 1, pos)) + } + }) { + ControlFlow::Break(x) | ControlFlow::Continue((x, _)) => x, + } +} - let chunks = WalkDir::new(project_root.join("tests")) - .into_iter() - .filter_map(|entry| { - let entry = entry.expect("failed to find tests"); - let path = entry.path(); +/// Formats the configuration list in `clippy_config/src/conf.rs` +#[expect(clippy::too_many_lines)] +fn fmt_conf(check: bool) -> Result<(), Error> { + #[derive(Clone, Copy)] + enum State { + Start, + Docs, + Pound, + OpenBracket, + Attr(u32), + Lints, + EndLints, + Field, + } - if path.extension() != Some("rs".as_ref()) || entry.file_name() == "ice-3891.rs" { - None - } else { - Some(entry.into_path().into_os_string()) - } - }) - .chunks(250); + let path: PathBuf = [ + clippy_project_root().as_path(), + "clippy_config".as_ref(), + "src".as_ref(), + "conf.rs".as_ref(), + ] + .into_iter() + .collect(); + let text = fs::read_to_string(&path)?; - for chunk in &chunks { - success &= rustfmt(context, chunk)?; - } + let (pre, conf) = text + .split_once("define_Conf! {\n") + .expect("can't find config definition"); + let (conf, post) = conf.split_once("\n}\n").expect("can't find config definition"); + let conf_offset = pre.len() + 15; - Ok(success) - } + let mut pos = 0u32; + let mut attrs_start = 0; + let mut attrs_end = 0; + let mut field_start = 0; + let mut lints = Vec::new(); + let mut name = ""; + let mut fields = Vec::new(); + let mut state = State::Start; - fn output_err(err: CliError) { - match err { - CliError::CommandFailed(command, stderr) => { - eprintln!("error: A command failed! `{command}`\nstderr: {stderr}"); + for (i, t) in tokenize(conf) + .map(|x| { + let start = pos; + pos += x.len; + (start as usize, x) + }) + .filter(|(_, t)| !matches!(t.kind, TokenKind::Whitespace)) + { + match (state, t.kind) { + (State::Start, TokenKind::LineComment { doc_style: Some(_) }) => { + attrs_start = i; + attrs_end = i + t.len as usize; + state = State::Docs; }, - CliError::IoError(err) => { - eprintln!("error: {err}"); + (State::Start, TokenKind::Pound) => { + attrs_start = i; + attrs_end = i; + state = State::Pound; }, - CliError::RustfmtNotInstalled => { - eprintln!("error: rustfmt nightly is not installed."); + (State::Docs, TokenKind::LineComment { doc_style: Some(_) }) => attrs_end = i + t.len as usize, + (State::Docs, TokenKind::Pound) => state = State::Pound, + (State::Pound, TokenKind::OpenBracket) => state = State::OpenBracket, + (State::OpenBracket, TokenKind::Ident) => { + state = if conf[i..i + t.len as usize] == *"lints" { + State::Lints + } else { + State::Attr(0) + }; }, - CliError::WalkDirError(err) => { - eprintln!("error: {err}"); + (State::Attr(0), TokenKind::CloseBracket) => { + attrs_end = i + 1; + state = State::Docs; }, - CliError::IntellijSetupActive => { - eprintln!( - "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`. -Not formatting because that would format the local repo as well! -Please revert the changes to Cargo.tomls with `cargo dev remove intellij`." - ); + (State::Attr(x), TokenKind::OpenParen | TokenKind::OpenBracket | TokenKind::OpenBrace) => { + state = State::Attr(x + 1); + }, + (State::Attr(x), TokenKind::CloseParen | TokenKind::CloseBracket | TokenKind::CloseBrace) => { + state = State::Attr(x - 1); + }, + (State::Lints, TokenKind::Ident) => lints.push(&conf[i..i + t.len as usize]), + (State::Lints, TokenKind::CloseBracket) => state = State::EndLints, + (State::EndLints | State::Docs, TokenKind::Ident) => { + field_start = i; + name = &conf[i..i + t.len as usize]; + state = State::Field; + }, + (State::Field, TokenKind::LineComment { doc_style: Some(_) }) => { + #[expect(clippy::drain_collect)] + fields.push(ClippyConf { + name, + lints: lints.drain(..).collect(), + attrs: &conf[attrs_start..attrs_end], + field: conf[field_start..i].trim_end(), + }); + attrs_start = i; + attrs_end = i + t.len as usize; + state = State::Docs; + }, + (State::Field, TokenKind::Pound) => { + #[expect(clippy::drain_collect)] + fields.push(ClippyConf { + name, + lints: lints.drain(..).collect(), + attrs: &conf[attrs_start..attrs_end], + field: conf[field_start..i].trim_end(), + }); + attrs_start = i; + attrs_end = i; + state = State::Pound; + }, + (State::Field | State::Attr(_), _) + | (State::Lints, TokenKind::Comma | TokenKind::OpenParen | TokenKind::CloseParen) => {}, + _ => { + return Err(Error::Parse( + path, + offset_to_line(&text, conf_offset + i), + format!("unexpected token `{}`", &conf[i..i + t.len as usize]), + )); }, } } + if !matches!(state, State::Field) { + return Err(Error::Parse( + path, + offset_to_line(&text, conf_offset + conf.len()), + "incomplete field".into(), + )); + } + fields.push(ClippyConf { + name, + lints, + attrs: &conf[attrs_start..attrs_end], + field: conf[field_start..].trim_end(), + }); + + for field in &mut fields { + field.lints.sort_unstable(); + } + fields.sort_by_key(|x| x.name); + + let new_text = format!( + "{pre}define_Conf! {{\n{}}}\n{post}", + fields.iter().format_with("", |field, f| { + if field.lints.is_empty() { + f(&format_args!(" {}\n {}\n", field.attrs, field.field)) + } else if field.lints.iter().map(|x| x.len() + 2).sum::() < 120 - 14 { + f(&format_args!( + " {}\n #[lints({})]\n {}\n", + field.attrs, + field.lints.iter().join(", "), + field.field, + )) + } else { + f(&format_args!( + " {}\n #[lints({}\n )]\n {}\n", + field.attrs, + field + .lints + .iter() + .format_with("", |x, f| f(&format_args!("\n {x},"))), + field.field, + )) + } + }) + ); + + if text != new_text { + if check { + return Err(Error::CheckFailed); + } + fs::write(&path, new_text.as_bytes())?; + } + Ok(()) +} + +fn run_rustfmt(context: &FmtContext) -> Result<(), Error> { + let project_root = clippy_project_root(); + + // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to + // format because rustfmt would also format the entire rustc repo as it is a local + // dependency + if fs::read_to_string(project_root.join("Cargo.toml")) + .expect("Failed to read clippy Cargo.toml") + .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]") + { + return Err(Error::IntellijSetupActive); + } + + check_for_rustfmt(context)?; + + cargo_fmt(context, project_root.as_path())?; + cargo_fmt(context, &project_root.join("clippy_dev"))?; + cargo_fmt(context, &project_root.join("rustc_tools_util"))?; + cargo_fmt(context, &project_root.join("lintcheck"))?; + + let chunks = WalkDir::new(project_root.join("tests")) + .into_iter() + .filter_map(|entry| { + let entry = entry.expect("failed to find tests"); + let path = entry.path(); + + if path.extension() != Some("rs".as_ref()) || entry.file_name() == "ice-3891.rs" { + None + } else { + Some(entry.into_path().into_os_string()) + } + }) + .chunks(250); + + for chunk in &chunks { + rustfmt(context, chunk)?; + } + Ok(()) +} + +// the "main" function of cargo dev fmt +pub fn run(check: bool, verbose: bool) { let output = Command::new("rustup") .args(["which", "rustfmt"]) .stderr(Stdio::inherit()) @@ -120,21 +324,10 @@ Please revert the changes to Cargo.tomls with `cargo dev remove intellij`." verbose, rustfmt_path, }; - let result = try_run(&context); - let code = match result { - Ok(true) => 0, - Ok(false) => { - eprintln!(); - eprintln!("Formatting check failed."); - eprintln!("Run `cargo dev fmt` to update formatting."); - 1 - }, - Err(err) => { - output_err(err); - 1 - }, - }; - process::exit(code); + if let Err(e) = run_rustfmt(&context).and_then(|()| fmt_conf(check)) { + e.display(); + process::exit(1); + } } fn format_command(program: impl AsRef, dir: impl AsRef, args: &[impl AsRef]) -> String { @@ -148,12 +341,12 @@ fn format_command(program: impl AsRef, dir: impl AsRef, args: &[imp ) } -fn exec( +fn exec_fmt_command( context: &FmtContext, program: impl AsRef, dir: impl AsRef, args: &[impl AsRef], -) -> Result { +) -> Result<(), Error> { if context.verbose { println!("{}", format_command(&program, &dir, args)); } @@ -166,28 +359,28 @@ fn exec( .unwrap(); let success = output.status.success(); - if !context.check && !success { - let stderr = std::str::from_utf8(&output.stderr).unwrap_or(""); - return Err(CliError::CommandFailed( - format_command(&program, &dir, args), - String::from(stderr), - )); + match (context.check, success) { + (_, true) => Ok(()), + (true, false) => Err(Error::CheckFailed), + (false, false) => { + let stderr = std::str::from_utf8(&output.stderr).unwrap_or(""); + Err(Error::CommandFailed( + format_command(&program, &dir, args), + String::from(stderr), + )) + }, } - - Ok(success) } -fn cargo_fmt(context: &FmtContext, path: &Path) -> Result { +fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<(), Error> { let mut args = vec!["fmt", "--all"]; if context.check { args.push("--check"); } - let success = exec(context, "cargo", path, &args)?; - - Ok(success) + exec_fmt_command(context, "cargo", path, &args) } -fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> { +fn check_for_rustfmt(context: &FmtContext) -> Result<(), Error> { let program = "rustfmt"; let dir = std::env::current_dir()?; let args = &["--version"]; @@ -204,23 +397,20 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> { .unwrap_or("") .starts_with("error: 'rustfmt' is not installed") { - Err(CliError::RustfmtNotInstalled) + Err(Error::RustfmtNotInstalled) } else { - Err(CliError::CommandFailed( + Err(Error::CommandFailed( format_command(program, &dir, args), std::str::from_utf8(&output.stderr).unwrap_or("").to_string(), )) } } -fn rustfmt(context: &FmtContext, paths: impl Iterator) -> Result { +fn rustfmt(context: &FmtContext, paths: impl Iterator) -> Result<(), Error> { let mut args = Vec::new(); if context.check { args.push(OsString::from("--check")); } args.extend(paths); - - let success = exec(context, &context.rustfmt_path, std::env::current_dir()?, &args)?; - - Ok(success) + exec_fmt_command(context, &context.rustfmt_path, std::env::current_dir()?, &args) }