1 use cargo_metadata::Metadata;
2 use clippy_utils::diagnostics::span_lint_and_help;
3 use rustc_lint::LateContext;
4 use rustc_span::source_map::DUMMY_SP;
6 use super::{NEGATIVE_FEATURE_NAMES, REDUNDANT_FEATURE_NAMES};
8 static PREFIXES: [&str; 8] = ["no-", "no_", "not-", "not_", "use-", "use_", "with-", "with_"];
9 static SUFFIXES: [&str; 2] = ["-support", "_support"];
11 pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) {
12 for package in &metadata.packages {
13 let mut features: Vec<&String> = package.features.keys().collect();
15 for feature in features {
17 let i = PREFIXES.partition_point(|prefix| prefix < &feature.as_str());
18 if i > 0 && feature.starts_with(PREFIXES[i - 1]) {
24 if let Some(prefix) = prefix_opt {
25 lint(cx, feature, prefix, true);
28 let suffix_opt: Option<&str> = {
29 let i = SUFFIXES.partition_point(|suffix| {
30 suffix.bytes().rev().cmp(feature.bytes().rev()) == std::cmp::Ordering::Less
32 if i > 0 && feature.ends_with(SUFFIXES[i - 1]) {
38 if let Some(suffix) = suffix_opt {
39 lint(cx, feature, suffix, false);
45 fn is_negative_prefix(s: &str) -> bool {
49 fn lint(cx: &LateContext<'_>, feature: &str, substring: &str, is_prefix: bool) {
50 let is_negative = is_prefix && is_negative_prefix(substring);
54 NEGATIVE_FEATURE_NAMES
56 REDUNDANT_FEATURE_NAMES
60 "the \"{substring}\" {} in the feature name \"{feature}\" is {}",
61 if is_prefix { "prefix" } else { "suffix" },
62 if is_negative { "negative" } else { "redundant" }
66 "consider renaming the feature to \"{}\"{}",
68 feature.strip_prefix(substring)
70 feature.strip_suffix(substring)
74 ", but make sure the feature adds functionality"
83 fn test_prefixes_sorted() {
84 let mut sorted_prefixes = PREFIXES;
85 sorted_prefixes.sort_unstable();
86 assert_eq!(PREFIXES, sorted_prefixes);
87 let mut sorted_suffixes = SUFFIXES;
88 sorted_suffixes.sort_by(|a, b| a.bytes().rev().cmp(b.bytes().rev()));
89 assert_eq!(SUFFIXES, sorted_suffixes);