Skip to content

Commit 783108d

Browse files
committed
Merge lint with single_char_pattern
1 parent 260e9ed commit 783108d

File tree

7 files changed

+108
-83
lines changed

7 files changed

+108
-83
lines changed

clippy_lints/src/lib.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,6 @@ mod repeat_once;
286286
mod returns;
287287
mod serde_api;
288288
mod shadow;
289-
mod single_char_push_str;
290289
mod single_component_path_imports;
291290
mod slow_vector_initialization;
292291
mod stable_sort_primitive;
@@ -676,6 +675,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
676675
&methods::SEARCH_IS_SOME,
677676
&methods::SHOULD_IMPLEMENT_TRAIT,
678677
&methods::SINGLE_CHAR_PATTERN,
678+
&methods::SINGLE_CHAR_PUSH_STR,
679679
&methods::SKIP_WHILE_NEXT,
680680
&methods::STRING_EXTEND_CHARS,
681681
&methods::SUSPICIOUS_MAP,
@@ -773,7 +773,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
773773
&shadow::SHADOW_REUSE,
774774
&shadow::SHADOW_SAME,
775775
&shadow::SHADOW_UNRELATED,
776-
&single_char_push_str::SINGLE_CHAR_PUSH_STR,
777776
&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
778777
&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
779778
&stable_sort_primitive::STABLE_SORT_PRIMITIVE,
@@ -930,7 +929,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
930929
store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
931930
store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
932931
store.register_late_pass(|| box strings::StringLitAsBytes);
933-
store.register_late_pass(|| box single_char_push_str::SingleCharPushStrPass);
934932
store.register_late_pass(|| box derive::Derive);
935933
store.register_late_pass(|| box types::CharLitAsU8);
936934
store.register_late_pass(|| box vec::UselessVec);
@@ -1346,6 +1344,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13461344
LintId::of(&methods::SEARCH_IS_SOME),
13471345
LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT),
13481346
LintId::of(&methods::SINGLE_CHAR_PATTERN),
1347+
LintId::of(&methods::SINGLE_CHAR_PUSH_STR),
13491348
LintId::of(&methods::SKIP_WHILE_NEXT),
13501349
LintId::of(&methods::STRING_EXTEND_CHARS),
13511350
LintId::of(&methods::SUSPICIOUS_MAP),
@@ -1412,7 +1411,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
14121411
LintId::of(&returns::NEEDLESS_RETURN),
14131412
LintId::of(&returns::UNUSED_UNIT),
14141413
LintId::of(&serde_api::SERDE_API_MISUSE),
1415-
LintId::of(&single_char_push_str::SINGLE_CHAR_PUSH_STR),
14161414
LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
14171415
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
14181416
LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
@@ -1527,6 +1525,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
15271525
LintId::of(&methods::OPTION_MAP_OR_NONE),
15281526
LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION),
15291527
LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT),
1528+
LintId::of(&methods::SINGLE_CHAR_PUSH_STR),
15301529
LintId::of(&methods::STRING_EXTEND_CHARS),
15311530
LintId::of(&methods::UNNECESSARY_FOLD),
15321531
LintId::of(&methods::WRONG_SELF_CONVENTION),
@@ -1551,7 +1550,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
15511550
LintId::of(&regex::TRIVIAL_REGEX),
15521551
LintId::of(&returns::NEEDLESS_RETURN),
15531552
LintId::of(&returns::UNUSED_UNIT),
1554-
LintId::of(&single_char_push_str::SINGLE_CHAR_PUSH_STR),
15551553
LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
15561554
LintId::of(&strings::STRING_LIT_AS_BYTES),
15571555
LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),

clippy_lints/src/methods/mod.rs

+75-14
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,29 @@ declare_clippy_lint! {
13061306
"using `.iter().next()` on a sliced array, which can be shortened to just `.get()`"
13071307
}
13081308

1309+
declare_clippy_lint! {
1310+
/// **What it does:** Warns when using push_str with a single-character string literal,
1311+
/// and push with a char would work fine.
1312+
///
1313+
/// **Why is this bad?** it's less clear that we are pushing a single character
1314+
///
1315+
/// **Known problems:** None
1316+
///
1317+
/// **Example:**
1318+
/// ```
1319+
/// let mut string = String::new();
1320+
/// string.push_str("R");
1321+
/// ```
1322+
/// Could be written as
1323+
/// ```
1324+
/// let mut string = String::new();
1325+
/// string.push('R');
1326+
/// ```
1327+
pub SINGLE_CHAR_PUSH_STR,
1328+
style,
1329+
"`push_str()` used with a single-character string literal as parameter"
1330+
}
1331+
13091332
declare_lint_pass!(Methods => [
13101333
UNWRAP_USED,
13111334
EXPECT_USED,
@@ -1327,6 +1350,7 @@ declare_lint_pass!(Methods => [
13271350
INEFFICIENT_TO_STRING,
13281351
NEW_RET_NO_SELF,
13291352
SINGLE_CHAR_PATTERN,
1353+
SINGLE_CHAR_PUSH_STR,
13301354
SEARCH_IS_SOME,
13311355
TEMPORARY_CSTRING_AS_PTR,
13321356
FILTER_NEXT,
@@ -1441,6 +1465,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
14411465
inefficient_to_string::lint(cx, expr, &args[0], self_ty);
14421466
}
14431467

1468+
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
1469+
if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
1470+
lint_single_char_push_string(cx, expr, args);
1471+
}
1472+
}
1473+
14441474
match self_ty.kind {
14451475
ty::Ref(_, ty, _) if ty.kind == ty::Str => {
14461476
for &(method, pos) in &PATTERN_METHODS {
@@ -3124,15 +3154,18 @@ fn lint_chars_last_cmp_with_unwrap<'tcx>(cx: &LateContext<'tcx>, info: &BinaryEx
31243154
}
31253155
}
31263156

3127-
/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
3128-
fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
3157+
fn get_hint_if_single_char_arg<'tcx>(
3158+
cx: &LateContext<'tcx>,
3159+
arg: &'tcx hir::Expr<'_>,
3160+
applicability: &mut Applicability,
3161+
) -> Option<String> {
31293162
if_chain! {
31303163
if let hir::ExprKind::Lit(lit) = &arg.kind;
31313164
if let ast::LitKind::Str(r, style) = lit.node;
3132-
if r.as_str().len() == 1;
3165+
let string = r.as_str();
3166+
if string.len() == 1;
31333167
then {
3134-
let mut applicability = Applicability::MachineApplicable;
3135-
let snip = snippet_with_applicability(cx, arg.span, "..", &mut applicability);
3168+
let snip = snippet_with_applicability(cx, arg.span, &string, applicability);
31363169
let ch = if let ast::StrStyle::Raw(nhash) = style {
31373170
let nhash = nhash as usize;
31383171
// for raw string: r##"a"##
@@ -3142,19 +3175,47 @@ fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr
31423175
&snip[1..(snip.len() - 1)]
31433176
};
31443177
let hint = format!("'{}'", if ch == "'" { "\\'" } else { ch });
3145-
span_lint_and_sugg(
3146-
cx,
3147-
SINGLE_CHAR_PATTERN,
3148-
arg.span,
3149-
"single-character string constant used as pattern",
3150-
"try using a `char` instead",
3151-
hint,
3152-
applicability,
3153-
);
3178+
Some(hint)
3179+
} else {
3180+
None
31543181
}
31553182
}
31563183
}
31573184

3185+
/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
3186+
fn lint_single_char_pattern<'tcx>(cx: &LateContext<'tcx>, _expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
3187+
let mut applicability = Applicability::MachineApplicable;
3188+
if let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability) {
3189+
span_lint_and_sugg(
3190+
cx,
3191+
SINGLE_CHAR_PATTERN,
3192+
arg.span,
3193+
"single-character string constant used as pattern",
3194+
"try using a `char` instead",
3195+
hint,
3196+
applicability,
3197+
);
3198+
}
3199+
}
3200+
3201+
/// lint for length-1 `str`s as argument for `push_str`
3202+
fn lint_single_char_push_string<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, args: &'tcx [hir::Expr<'_>]) {
3203+
let mut applicability = Applicability::MachineApplicable;
3204+
if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
3205+
let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
3206+
let sugg = format!("{}.push({})", base_string_snippet, extension_string);
3207+
span_lint_and_sugg(
3208+
cx,
3209+
SINGLE_CHAR_PUSH_STR,
3210+
expr.span,
3211+
"calling `push_str()` using a single-character string literal",
3212+
"consider using `push` with a character literal",
3213+
sugg,
3214+
applicability,
3215+
);
3216+
}
3217+
}
3218+
31583219
/// Checks for the `USELESS_ASREF` lint.
31593220
fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) {
31603221
// when we get here, we've already checked that the call name is "as_ref" or "as_mut"

clippy_lints/src/single_char_push_str.rs

-62
This file was deleted.

src/lintlist/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2003,7 +2003,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
20032003
group: "style",
20042004
desc: "`push_str()` used with a single-character string literal as parameter",
20052005
deprecation: None,
2006-
module: "single_char_push_str",
2006+
module: "methods",
20072007
},
20082008
Lint {
20092009
name: "single_component_path_imports",

tests/ui/single_char_push_str.fixed

+5
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,9 @@ fn main() {
77
string.push('\'');
88

99
string.push('u');
10+
string.push_str("st");
11+
string.push_str("");
12+
string.push('\x52');
13+
string.push('\u{0052}');
14+
string.push('a');
1015
}

tests/ui/single_char_push_str.rs

+5
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,9 @@ fn main() {
77
string.push_str("'");
88

99
string.push('u');
10+
string.push_str("st");
11+
string.push_str("");
12+
string.push_str("\x52");
13+
string.push_str("\u{0052}");
14+
string.push_str(r##"a"##);
1015
}

tests/ui/single_char_push_str.stderr

+19-1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,23 @@ error: calling `push_str()` using a single-character string literal
1212
LL | string.push_str("'");
1313
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')`
1414

15-
error: aborting due to 2 previous errors
15+
error: calling `push_str()` using a single-character string literal
16+
--> $DIR/single_char_push_str.rs:12:5
17+
|
18+
LL | string.push_str("/x52");
19+
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')`
20+
21+
error: calling `push_str()` using a single-character string literal
22+
--> $DIR/single_char_push_str.rs:13:5
23+
|
24+
LL | string.push_str("/u{0052}");
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')`
26+
27+
error: calling `push_str()` using a single-character string literal
28+
--> $DIR/single_char_push_str.rs:14:5
29+
|
30+
LL | string.push_str(r##"a"##);
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')`
32+
33+
error: aborting due to 5 previous errors
1634

0 commit comments

Comments
 (0)