about summary refs log tree commit diff
diff options
context:
space:
mode:
authorxFrednet <xFrednet@gmail.com>2021-05-11 20:23:52 +0200
committerxFrednet <xFrednet@gmail.com>2021-05-12 17:31:00 +0200
commit210ec728e5d7f428b22b78ee721ed6507cc6f925 (patch)
tree4e47ff7f5ecd6182f8d6b1c56f502c84a5a089b2
parentaa15a5442a975180a367373e563b7f8c626b5344 (diff)
downloadrust-210ec728e5d7f428b22b78ee721ed6507cc6f925.tar.gz
rust-210ec728e5d7f428b22b78ee721ed6507cc6f925.zip
Metadata collection monster searching for configurations
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--clippy_lints/src/utils/conf.rs24
-rw-r--r--clippy_lints/src/utils/internal_lints/metadata_collector.rs88
3 files changed, 109 insertions, 5 deletions
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 0c86441cf3f..f0fae6ee1c7 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -1009,7 +1009,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     #[cfg(feature = "metadata-collector-lint")]
     {
         if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
-            store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::default());
+            store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::new());
         }
     }
 
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 52c1dc3bdd2..98b86f73a1f 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -26,13 +26,13 @@ impl TryConf {
 
 macro_rules! define_Conf {
     ($(
-        #[$doc:meta]
+        #[doc = $doc:literal]
         $(#[conf_deprecated($dep:literal)])?
         ($name:ident: $ty:ty = $default:expr),
     )*) => {
         /// Clippy lint configuration
         pub struct Conf {
-            $(#[$doc] pub $name: $ty,)*
+            $(#[doc = $doc] pub $name: $ty,)*
         }
 
         mod defaults {
@@ -89,6 +89,24 @@ macro_rules! define_Conf {
                 Ok(TryConf { conf, errors })
             }
         }
+
+        #[cfg(feature = "metadata-collector-lint")]
+        pub mod metadata {
+            use crate::utils::internal_lints::metadata_collector::ClippyConfigurationBasicInfo;
+
+            pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfigurationBasicInfo> {
+                vec![
+                    $(
+                        ClippyConfigurationBasicInfo {
+                            name: stringify!($name),
+                            config_type: stringify!($ty),
+                            default: stringify!($default),
+                            doc_comment: $doc,
+                        },
+                    )+
+                ]
+            }
+        }
     };
 }
 
@@ -100,7 +118,7 @@ define_Conf! {
     (blacklisted_names: Vec<String> = ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
     /// Lint: COGNITIVE_COMPLEXITY. The maximum cognitive complexity a function can have
     (cognitive_complexity_threshold: u64 = 25),
-    /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. Use the Cognitive Complexity lint instead.
+    /// Lint: CYCLOMATIC_COMPLEXITY. Use the Cognitive Complexity lint instead.
     #[conf_deprecated("Please use `cognitive-complexity-threshold` instead")]
     (cyclomatic_complexity_threshold: Option<u64> = None),
     /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index fc4912ba52f..308f61beec3 100644
--- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -102,13 +102,24 @@ declare_clippy_lint! {
 impl_lint_pass!(MetadataCollector => [INTERNAL_METADATA_COLLECTOR]);
 
 #[allow(clippy::module_name_repetitions)]
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone)]
 pub struct MetadataCollector {
     /// All collected lints
     ///
     /// We use a Heap here to have the lints added in alphabetic order in the export
     lints: BinaryHeap<LintMetadata>,
     applicability_info: FxHashMap<String, ApplicabilityInfo>,
+    config: Vec<ClippyConfiguration>,
+}
+
+impl MetadataCollector {
+    pub fn new() -> Self {
+        Self {
+            lints: BinaryHeap::<LintMetadata>::default(),
+            applicability_info: FxHashMap::<String, ApplicabilityInfo>::default(),
+            config: collect_configs(),
+        }
+    }
 }
 
 impl Drop for MetadataCollector {
@@ -214,6 +225,81 @@ impl Serialize for ApplicabilityInfo {
     }
 }
 
+#[derive(Debug)]
+pub(crate) struct ClippyConfigurationBasicInfo {
+    pub name: &'static str,
+    pub config_type: &'static str,
+    pub default: &'static str,
+    pub doc_comment: &'static str,
+}
+
+#[derive(Debug, Clone, Default)]
+struct ClippyConfiguration {
+    name: String,
+    lints: Vec<String>,
+    doc: String,
+    config_type: &'static str,
+    default: String,
+}
+
+// ==================================================================
+// Configuration
+// ==================================================================
+fn collect_configs() -> Vec<ClippyConfiguration> {
+    let cons = crate::utils::conf::metadata::get_configuration_metadata();
+    cons.iter()
+        .map(move |x| {
+            let (lints, doc) = parse_config_field_doc(x.doc_comment)
+                .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string()));
+
+            ClippyConfiguration {
+                name: to_kebab(x.name),
+                lints,
+                doc,
+                config_type: x.config_type,
+                default: x.default.to_string(),
+            }
+        })
+        .collect()
+}
+
+/// 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>, String)> {
+    const DOC_START: &str = " Lint: ";
+    if_chain! {
+        if doc_comment.starts_with(DOC_START);
+        if let Some(split_pos) = doc_comment.find('.');
+        then {
+            let mut doc_comment = doc_comment.to_string();
+            let documentation = doc_comment.split_off(split_pos);
+
+            doc_comment.make_ascii_lowercase();
+            let lints: Vec<String> = doc_comment.split_off(DOC_START.len()).split(", ").map(str::to_string).collect();
+
+            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('_', "-")
+}
+
+// ==================================================================
+// Lint pass
+// ==================================================================
 impl<'hir> LateLintPass<'hir> for MetadataCollector {
     /// Collecting lint declarations like:
     /// ```rust, ignore