]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/enum_variants.rs
Auto merge of #3946 - rchaser53:issue-3920, r=flip1995
[rust.git] / clippy_lints / src / enum_variants.rs
index 860cd69303e0500e968f5fe021eeb18db9a5d339..707fe93bd0c3c43d81b9ca9b1595f7edcc6fa578 100644 (file)
 //! lint on enum variants that are prefixed or suffixed by the same characters
 
-use rustc::lint::*;
+use crate::utils::{camel_case, in_macro};
+use crate::utils::{span_help_and_lint, span_lint};
+use rustc::lint::{EarlyContext, EarlyLintPass, Lint, LintArray, LintPass};
+use rustc::{declare_tool_lint, lint_array};
 use syntax::ast::*;
-use syntax::codemap::Span;
-use syntax::symbol::LocalInternedString;
-use utils::{span_help_and_lint, span_lint};
-use utils::{camel_case_from, camel_case_until, in_macro};
+use syntax::source_map::Span;
+use syntax::symbol::{InternedString, LocalInternedString};
 
-/// **What it does:** Detects enumeration variants that are prefixed or suffixed
-/// by the same characters.
-///
-/// **Why is this bad?** Enumeration variant names should specify their variant,
-/// not repeat the enumeration name.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// enum Cake {
-///     BlackForestCake,
-///     HummingbirdCake,
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Detects enumeration variants that are prefixed or suffixed
+    /// by the same characters.
+    ///
+    /// **Why is this bad?** Enumeration variant names should specify their variant,
+    /// not repeat the enumeration name.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// enum Cake {
+    ///     BlackForestCake,
+    ///     HummingbirdCake,
+    ///     BattenbergCake,
+    /// }
+    /// ```
     pub ENUM_VARIANT_NAMES,
     style,
     "enums where all variants share a prefix/postfix"
 }
 
-/// **What it does:** Detects enumeration variants that are prefixed or suffixed
-/// by the same characters.
-///
-/// **Why is this bad?** Enumeration variant names should specify their variant,
-/// not repeat the enumeration name.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// enum Cake {
-///     BlackForestCake,
-///     HummingbirdCake,
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Detects enumeration variants that are prefixed or suffixed
+    /// by the same characters.
+    ///
+    /// **Why is this bad?** Enumeration variant names should specify their variant,
+    /// not repeat the enumeration name.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// enum Cake {
+    ///     BlackForestCake,
+    ///     HummingbirdCake,
+    ///     BattenbergCake,
+    /// }
+    /// ```
     pub PUB_ENUM_VARIANT_NAMES,
     pedantic,
     "enums where all variants share a prefix/postfix"
 }
 
-/// **What it does:** Detects type names that are prefixed or suffixed by the
-/// containing module's name.
-///
-/// **Why is this bad?** It requires the user to type the module name twice.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// mod cake {
-///     struct BlackForestCake;
-/// }
-/// ```
 declare_clippy_lint! {
-    pub STUTTER,
+    /// **What it does:** Detects type names that are prefixed or suffixed by the
+    /// containing module's name.
+    ///
+    /// **Why is this bad?** It requires the user to type the module name twice.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// mod cake {
+    ///     struct BlackForestCake;
+    /// }
+    /// ```
+    pub MODULE_NAME_REPETITIONS,
     pedantic,
     "type names prefixed/postfixed with their containing module's name"
 }
 
-/// **What it does:** Checks for modules that have the same name as their
-/// parent module
-///
-/// **Why is this bad?** A typical beginner mistake is to have `mod foo;` and
-/// again `mod foo { ..
-/// }` in `foo.rs`.
-/// The expectation is that items inside the inner `mod foo { .. }` are then
-/// available
-/// through `foo::x`, but they are only available through
-/// `foo::foo::x`.
-/// If this is done on purpose, it would be better to choose a more
-/// representative module name.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// // lib.rs
-/// mod foo;
-/// // foo.rs
-/// mod foo {
-///     ...
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for modules that have the same name as their
+    /// parent module
+    ///
+    /// **Why is this bad?** A typical beginner mistake is to have `mod foo;` and
+    /// again `mod foo { ..
+    /// }` in `foo.rs`.
+    /// The expectation is that items inside the inner `mod foo { .. }` are then
+    /// available
+    /// through `foo::x`, but they are only available through
+    /// `foo::foo::x`.
+    /// If this is done on purpose, it would be better to choose a more
+    /// representative module name.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```ignore
+    /// // lib.rs
+    /// mod foo;
+    /// // foo.rs
+    /// mod foo {
+    ///     ...
+    /// }
+    /// ```
     pub MODULE_INCEPTION,
     style,
     "modules that have the same name as their parent module"
 }
 
 pub struct EnumVariantNames {
-    modules: Vec<(LocalInternedString, String)>,
+    modules: Vec<(InternedString, String)>,
     threshold: u64,
 }
 
@@ -114,22 +117,28 @@ pub fn new(threshold: u64) -> Self {
 
 impl LintPass for EnumVariantNames {
     fn get_lints(&self) -> LintArray {
-        lint_array!(ENUM_VARIANT_NAMES, PUB_ENUM_VARIANT_NAMES, STUTTER, MODULE_INCEPTION)
+        lint_array!(
+            ENUM_VARIANT_NAMES,
+            PUB_ENUM_VARIANT_NAMES,
+            MODULE_NAME_REPETITIONS,
+            MODULE_INCEPTION
+        )
+    }
+
+    fn name(&self) -> &'static str {
+        "EnumVariantNames"
     }
 }
 
 fn var2str(var: &Variant) -> LocalInternedString {
-    var.node.ident.name.as_str()
+    var.node.ident.as_str()
 }
 
 /// Returns the number of chars that match from the start
 fn partial_match(pre: &str, name: &str) -> usize {
     let mut name_iter = name.chars();
     let _ = name_iter.next_back(); // make sure the name is never fully matched
-    pre.chars()
-        .zip(name_iter)
-        .take_while(|&(l, r)| l == r)
-        .count()
+    pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count()
 }
 
 /// Returns the number of chars that match from the end
@@ -143,10 +152,8 @@ fn partial_rmatch(post: &str, name: &str) -> usize {
         .count()
 }
 
-// FIXME: #600
-#[allow(while_let_on_iterator)]
 fn check_variant(
-    cx: &EarlyContext,
+    cx: &EarlyContext<'_>,
     threshold: u64,
     def: &EnumDef,
     item_name: &str,
@@ -160,9 +167,7 @@ fn check_variant(
     for var in &def.variants {
         let name = var2str(var);
         if partial_match(item_name, &name) == item_name_chars
-            && name.chars()
-                .nth(item_name_chars)
-                .map_or(false, |c| !c.is_lowercase())
+            && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
         {
             span_lint(cx, lint, var.span, "Variant name starts with the enum's name");
         }
@@ -171,19 +176,19 @@ fn check_variant(
         }
     }
     let first = var2str(&def.variants[0]);
-    let mut pre = &first[..camel_case_until(&*first)];
-    let mut post = &first[camel_case_from(&*first)..];
+    let mut pre = &first[..camel_case::until(&*first)];
+    let mut post = &first[camel_case::from(&*first)..];
     for var in &def.variants {
         let name = var2str(var);
 
         let pre_match = partial_match(pre, &name);
         pre = &pre[..pre_match];
-        let pre_camel = camel_case_until(pre);
+        let pre_camel = camel_case::until(pre);
         pre = &pre[..pre_camel];
         while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
             if next.is_lowercase() {
                 let last = pre.len() - last.len_utf8();
-                let last_camel = camel_case_until(&pre[..last]);
+                let last_camel = camel_case::until(&pre[..last]);
                 pre = &pre[..last_camel];
             } else {
                 break;
@@ -193,7 +198,7 @@ fn check_variant(
         let post_match = partial_rmatch(post, &name);
         let post_end = post.len() - post_match;
         post = &post[post_end..];
-        let post_camel = camel_case_from(post);
+        let post_camel = camel_case::from(post);
         post = &post[post_camel..];
     }
     let (what, value) = match (pre.is_empty(), post.is_empty()) {
@@ -237,13 +242,14 @@ fn to_camel_case(item_name: &str) -> String {
 }
 
 impl EarlyLintPass for EnumVariantNames {
-    fn check_item_post(&mut self, _cx: &EarlyContext, _item: &Item) {
+    fn check_item_post(&mut self, _cx: &EarlyContext<'_>, _item: &Item) {
         let last = self.modules.pop();
         assert!(last.is_some());
     }
 
-    fn check_item(&mut self, cx: &EarlyContext, item: &Item) {
-        let item_name = item.ident.name.as_str();
+    #[allow(clippy::similar_names)]
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        let item_name = item.ident.as_str();
         let item_name_chars = item_name.chars().count();
         let item_camel = to_camel_case(&item_name);
         if !in_macro(item.span) {
@@ -260,24 +266,31 @@ fn check_item(&mut self, cx: &EarlyContext, item: &Item) {
                             );
                         }
                     }
-                    if item.vis.node == VisibilityKind::Public {
+                    if item.vis.node.is_pub() {
                         let matching = partial_match(mod_camel, &item_camel);
                         let rmatching = partial_rmatch(mod_camel, &item_camel);
                         let nchars = mod_camel.chars().count();
 
-                        let is_word_beginning = |c: char| {
-                            c == '_' || c.is_uppercase() || c.is_numeric()
-                        };
+                        let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();
 
                         if matching == nchars {
                             match item_camel.chars().nth(nchars) {
-                                Some(c) if is_word_beginning(c) =>
-                                    span_lint(cx, STUTTER, item.span, "item name starts with its containing module's name"),
-                                _ => ()
+                                Some(c) if is_word_beginning(c) => span_lint(
+                                    cx,
+                                    MODULE_NAME_REPETITIONS,
+                                    item.span,
+                                    "item name starts with its containing module's name",
+                                ),
+                                _ => (),
                             }
                         }
                         if rmatching == nchars {
-                            span_lint(cx, STUTTER, item.span, "item name ends with its containing module's name");
+                            span_lint(
+                                cx,
+                                MODULE_NAME_REPETITIONS,
+                                item.span,
+                                "item name ends with its containing module's name",
+                            );
                         }
                     }
                 }
@@ -290,6 +303,6 @@ fn check_item(&mut self, cx: &EarlyContext, item: &Item) {
             };
             check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span, lint);
         }
-        self.modules.push((item_name, item_camel));
+        self.modules.push((item_name.as_interned_str(), item_camel));
     }
 }