]> git.lizzy.rs Git - rust.git/commitdiff
Merge lint with `single_char_pattern`
authorChristoph Walcher <christoph-wa@gmx.de>
Fri, 14 Aug 2020 10:52:19 +0000 (12:52 +0200)
committerChristoph Walcher <christoph-wa@gmx.de>
Fri, 14 Aug 2020 23:40:55 +0000 (01:40 +0200)
clippy_lints/src/lib.rs
clippy_lints/src/methods/mod.rs
clippy_lints/src/single_char_push_str.rs [deleted file]
src/lintlist/mod.rs
tests/ui/single_char_push_str.fixed
tests/ui/single_char_push_str.rs
tests/ui/single_char_push_str.stderr

index 4f261ba932ea6922c66dfffea306b260dd620cd5..5e4a4a4f49cefdef4fd29420d0d0096435a09163 100644 (file)
@@ -287,7 +287,6 @@ macro_rules! declare_clippy_lint {
 mod returns;
 mod serde_api;
 mod shadow;
-mod single_char_push_str;
 mod single_component_path_imports;
 mod slow_vector_initialization;
 mod stable_sort_primitive;
@@ -678,6 +677,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &methods::SEARCH_IS_SOME,
         &methods::SHOULD_IMPLEMENT_TRAIT,
         &methods::SINGLE_CHAR_PATTERN,
+        &methods::SINGLE_CHAR_PUSH_STR,
         &methods::SKIP_WHILE_NEXT,
         &methods::STRING_EXTEND_CHARS,
         &methods::SUSPICIOUS_MAP,
@@ -776,7 +776,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &shadow::SHADOW_REUSE,
         &shadow::SHADOW_SAME,
         &shadow::SHADOW_UNRELATED,
-        &single_char_push_str::SINGLE_CHAR_PUSH_STR,
         &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
         &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
         &stable_sort_primitive::STABLE_SORT_PRIMITIVE,
@@ -934,7 +933,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
     store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
     store.register_late_pass(|| box strings::StringLitAsBytes);
-    store.register_late_pass(|| box single_char_push_str::SingleCharPushStrPass);
     store.register_late_pass(|| box derive::Derive);
     store.register_late_pass(|| box types::CharLitAsU8);
     store.register_late_pass(|| box vec::UselessVec);
@@ -1352,6 +1350,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&methods::SEARCH_IS_SOME),
         LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT),
         LintId::of(&methods::SINGLE_CHAR_PATTERN),
+        LintId::of(&methods::SINGLE_CHAR_PUSH_STR),
         LintId::of(&methods::SKIP_WHILE_NEXT),
         LintId::of(&methods::STRING_EXTEND_CHARS),
         LintId::of(&methods::SUSPICIOUS_MAP),
@@ -1419,7 +1418,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&returns::NEEDLESS_RETURN),
         LintId::of(&returns::UNUSED_UNIT),
         LintId::of(&serde_api::SERDE_API_MISUSE),
-        LintId::of(&single_char_push_str::SINGLE_CHAR_PUSH_STR),
         LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
         LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
         LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
@@ -1536,6 +1534,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&methods::OPTION_MAP_OR_NONE),
         LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION),
         LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT),
+        LintId::of(&methods::SINGLE_CHAR_PUSH_STR),
         LintId::of(&methods::STRING_EXTEND_CHARS),
         LintId::of(&methods::UNNECESSARY_FOLD),
         LintId::of(&methods::WRONG_SELF_CONVENTION),
@@ -1560,7 +1559,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&regex::TRIVIAL_REGEX),
         LintId::of(&returns::NEEDLESS_RETURN),
         LintId::of(&returns::UNUSED_UNIT),
-        LintId::of(&single_char_push_str::SINGLE_CHAR_PUSH_STR),
         LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
         LintId::of(&strings::STRING_LIT_AS_BYTES),
         LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
index b6266ef2ba19895560a1916fe7d866fbbcc241be..2986a5a59449ba58fcf7b8f42bb0b1945c458817 100644 (file)
     "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Warns when using push_str with a single-character string literal,
+    /// and push with a char would work fine.
+    ///
+    /// **Why is this bad?** it's less clear that we are pushing a single character
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```
+    /// let mut string = String::new();
+    /// string.push_str("R");
+    /// ```
+    /// Could be written as
+    /// ```
+    /// let mut string = String::new();
+    /// string.push('R');
+    /// ```
+    pub SINGLE_CHAR_PUSH_STR,
+    style,
+    "`push_str()` used with a single-character string literal as parameter"
+}
+
 declare_lint_pass!(Methods => [
     UNWRAP_USED,
     EXPECT_USED,
     INEFFICIENT_TO_STRING,
     NEW_RET_NO_SELF,
     SINGLE_CHAR_PATTERN,
+    SINGLE_CHAR_PUSH_STR,
     SEARCH_IS_SOME,
     TEMPORARY_CSTRING_AS_PTR,
     FILTER_NEXT,
@@ -1441,6 +1465,12 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
                     inefficient_to_string::lint(cx, expr, &args[0], self_ty);
                 }
 
+                if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
+                    if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
+                        lint_single_char_push_string(cx, expr, args);
+                    }
+                }
+
                 match self_ty.kind {
                     ty::Ref(_, ty, _) if ty.kind == ty::Str => {
                         for &(method, pos) in &PATTERN_METHODS {
@@ -3124,15 +3154,18 @@ fn lint_chars_last_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryEx
     }
 }
 
-/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
-fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
+fn get_hint_if_single_char_arg<'tcx>(
+    cx: &LateContext<'tcx>,
+    arg: &'tcx hir::Expr<'_>,
+    applicability: &mut Applicability,
+) -> Option<String> {
     if_chain! {
         if let hir::ExprKind::Lit(lit) = &arg.kind;
         if let ast::LitKind::Str(r, style) = lit.node;
-        if r.as_str().len() == 1;
+        let string = r.as_str();
+        if string.len() == 1;
         then {
-            let mut applicability = Applicability::MachineApplicable;
-            let snip = snippet_with_applicability(cx, arg.span, "..", &mut applicability);
+            let snip = snippet_with_applicability(cx, arg.span, &string, applicability);
             let ch = if let ast::StrStyle::Raw(nhash) = style {
                 let nhash = nhash as usize;
                 // for raw string: r##"a"##
@@ -3142,19 +3175,47 @@ fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr
                 &snip[1..(snip.len() - 1)]
             };
             let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch });
-            span_lint_and_sugg(
-                cx,
-                SINGLE_CHAR_PATTERN,
-                arg.span,
-                "single-character string constant used as pattern",
-                "try using a `char` instead",
-                hint,
-                applicability,
-            );
+            Some(hint)
+        } else {
+            None
         }
     }
 }
 
+/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
+fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
+    let mut applicability = Applicability::MachineApplicable;
+    if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) {
+        span_lint_and_sugg(
+            cx,
+            SINGLE_CHAR_PATTERN,
+            arg.span,
+            "single-character string constant used as pattern",
+            "try using a `char` instead",
+            hint,
+            applicability,
+        );
+    }
+}
+
+/// lint for length-1 `str`s as argument for `push_str`
+fn lint_single_char_push_string<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) {
+    let mut applicability = Applicability::MachineApplicable;
+    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
+        let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
+        let sugg = format!("{}.push({})", base_string_snippet, extension_string);
+        span_lint_and_sugg(
+            cx,
+            SINGLE_CHAR_PUSH_STR,
+            expr.span,
+            "calling `push_str()` using a single-character string literal",
+            "consider using `push` with a character literal",
+            sugg,
+            applicability,
+        );
+    }
+}
+
 /// Checks for the `USELESS_ASREF` lint.
 fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) {
     // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
diff --git a/clippy_lints/src/single_char_push_str.rs b/clippy_lints/src/single_char_push_str.rs
deleted file mode 100644 (file)
index 68bbef7..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-use crate::utils::{match_def_path, paths, snippet_with_applicability, span_lint_and_sugg};
-use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// **What it does:** Warns when using push_str with a single-character string literal,
-    /// and push with a char would work fine.
-    ///
-    /// **Why is this bad?** This is in all probability not the intended outcome. At
-    /// the least it hurts readability of the code.
-    ///
-    /// **Known problems:** None
-    ///
-    /// **Example:**
-    /// ```
-    /// let mut string = String::new();
-    /// string.push_str("R");
-    /// ```
-    /// Could be written as
-    /// ```
-    /// let mut string = String::new();
-    /// string.push('R');
-    /// ```
-    pub SINGLE_CHAR_PUSH_STR,
-    style,
-    "`push_str()` used with a single-character string literal as parameter"
-}
-
-declare_lint_pass!(SingleCharPushStrPass => [SINGLE_CHAR_PUSH_STR]);
-
-impl<'tcx> LateLintPass<'tcx> for SingleCharPushStrPass {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind;
-            if let [base_string, extension_string] = args;
-            if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
-            if match_def_path(cx, fn_def_id, &paths::PUSH_STR);
-            if let ExprKind::Lit(ref lit) = extension_string.kind;
-            if let LitKind::Str(symbol,_) = lit.node;
-            let extension_string_val = symbol.as_str().to_string();
-            if extension_string_val.len() == 1;
-            then {
-                let mut applicability = Applicability::MachineApplicable;
-                let base_string_snippet = snippet_with_applicability(cx, base_string.span, "_", &mut applicability);
-                let sugg = format!("{}.push({:?})", base_string_snippet, extension_string_val.chars().next().unwrap());
-                span_lint_and_sugg(
-                    cx,
-                    SINGLE_CHAR_PUSH_STR,
-                    expr.span,
-                    "calling `push_str()` using a single-character string literal",
-                    "consider using `push` with a character literal",
-                    sugg,
-                    applicability
-                );
-            }
-        }
-    }
-}
index 000ab8b8f36855fe04aa6e7e8160c56fbe86c5ce..4fd3277687438b2bec897b5494ed75ee977dac35 100644 (file)
         group: "style",
         desc: "`push_str()` used with a single-character string literal as parameter",
         deprecation: None,
-        module: "single_char_push_str",
+        module: "methods",
     },
     Lint {
         name: "single_component_path_imports",
index 49607c49218a2e184815015f7d77eda47d1099f4..0812c026a644fbdd84f05569edc5cf954a8a109f 100644 (file)
@@ -7,4 +7,9 @@ fn main() {
     string.push('\'');
 
     string.push('u');
+    string.push_str("st");
+    string.push_str("");
+    string.push('\x52');
+    string.push('\u{0052}');
+    string.push('a');
 }
index bbeebd027b16fe9f7b047981fe523ac0d90e1ee7..ab293bbe4eeb5ce8171ec28f610410a45f2d5cb8 100644 (file)
@@ -7,4 +7,9 @@ fn main() {
     string.push_str("'");
 
     string.push('u');
+    string.push_str("st");
+    string.push_str("");
+    string.push_str("\x52");
+    string.push_str("\u{0052}");
+    string.push_str(r##"a"##);
 }
index 453ec2d42f1f8c67edaaed332ee4341e5f3960df..0e9bdaa23e7e8474accd8321884cc0861db8405c 100644 (file)
@@ -12,5 +12,23 @@ error: calling `push_str()` using a single-character string literal
 LL |     string.push_str("'");
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')`
 
-error: aborting due to 2 previous errors
+error: calling `push_str()` using a single-character string literal
+  --> $DIR/single_char_push_str.rs:12:5
+   |
+LL |     string.push_str("/x52");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')`
+
+error: calling `push_str()` using a single-character string literal
+  --> $DIR/single_char_push_str.rs:13:5
+   |
+LL |     string.push_str("/u{0052}");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')`
+
+error: calling `push_str()` using a single-character string literal
+  --> $DIR/single_char_push_str.rs:14:5
+   |
+LL |     string.push_str(r##"a"##);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')`
+
+error: aborting due to 5 previous errors