Skip to content

Commit fdcd974

Browse files
committed
Merge pull request #565 from mcarton/or_fun_call
Handle Entry types in OR_FUN_CALL lint
2 parents 6fa49eb + 5ac6659 commit fdcd974

File tree

3 files changed

+44
-12
lines changed

3 files changed

+44
-12
lines changed

src/methods.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ use syntax::codemap::Span;
99

1010
use utils::{snippet, span_lint, span_note_and_lint, match_path, match_type, method_chain_args, match_trait_method,
1111
walk_ptrs_ty_depth, walk_ptrs_ty, get_trait_def_id, implements_trait};
12-
use utils::{DEFAULT_TRAIT_PATH, OPTION_PATH, RESULT_PATH, STRING_PATH};
12+
use utils::{
13+
BTREEMAP_ENTRY_PATH, DEFAULT_TRAIT_PATH, HASHMAP_ENTRY_PATH, OPTION_PATH,
14+
RESULT_PATH, STRING_PATH
15+
};
1316
use utils::MethodArgs;
1417
use rustc::middle::cstore::CrateStore;
1518

@@ -343,19 +346,31 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>])
343346
or_has_args: bool,
344347
span: Span
345348
) {
349+
// (path, fn_has_argument, methods)
350+
let know_types : &[(&[_], _, &[_], _)] = &[
351+
(&BTREEMAP_ENTRY_PATH, false, &["or_insert"], "with"),
352+
(&HASHMAP_ENTRY_PATH, false, &["or_insert"], "with"),
353+
(&OPTION_PATH, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
354+
(&RESULT_PATH, true, &["or", "unwrap_or"], "else"),
355+
];
356+
346357
let self_ty = cx.tcx.expr_ty(self_expr);
347358

348-
let is_result = if match_type(cx, self_ty, &RESULT_PATH) {
349-
true
350-
}
351-
else if match_type(cx, self_ty, &OPTION_PATH) {
352-
false
359+
let (fn_has_arguments, poss, suffix) =
360+
if let Some(&(_, fn_has_arguments, poss, suffix)) = know_types.iter().find(|&&i| {
361+
match_type(cx, self_ty, i.0)
362+
}) {
363+
(fn_has_arguments, poss, suffix)
364+
}
365+
else {
366+
return
367+
};
368+
369+
if !poss.contains(&name) {
370+
return
353371
}
354-
else {
355-
return;
356-
};
357372

358-
let sugg = match (is_result, !or_has_args) {
373+
let sugg = match (fn_has_arguments, !or_has_args) {
359374
(true, _) => format!("|_| {}", snippet(cx, arg.span, "..")),
360375
(false, false) => format!("|| {}", snippet(cx, arg.span, "..")),
361376
(false, true) => format!("{}", snippet(cx, fun.span, "..")),
@@ -364,13 +379,14 @@ fn lint_or_fun_call(cx: &LateContext, expr: &Expr, name: &str, args: &[P<Expr>])
364379
span_lint(cx, OR_FUN_CALL, span,
365380
&format!("use of `{}` followed by a function call", name))
366381
.span_suggestion(span, "try this",
367-
format!("{}.{}_else({})",
382+
format!("{}.{}_{}({})",
368383
snippet(cx, self_expr.span, "_"),
369384
name,
385+
suffix,
370386
sugg));
371387
}
372388

373-
if args.len() == 2 && ["map_or", "ok_or", "or", "unwrap_or"].contains(&name) {
389+
if args.len() == 2 {
374390
if let ExprCall(ref fun, ref or_args) = args[1].node {
375391
let or_has_args = !or_args.is_empty();
376392
if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {

src/utils.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ pub type MethodArgs = HirVec<P<Expr>>;
2020

2121
// module DefPaths for certain structs/enums we check for
2222
pub const BEGIN_UNWIND: [&'static str; 3] = ["std", "rt", "begin_unwind"];
23+
pub const BTREEMAP_ENTRY_PATH: [&'static str; 4] = ["collections", "btree", "map", "Entry"];
2324
pub const BTREEMAP_PATH: [&'static str; 4] = ["collections", "btree", "map", "BTreeMap"];
2425
pub const CLONE_PATH: [&'static str; 2] = ["Clone", "clone"];
2526
pub const COW_PATH: [&'static str; 3] = ["collections", "borrow", "Cow"];
2627
pub const DEFAULT_TRAIT_PATH: [&'static str; 3] = ["core", "default", "Default"];
28+
pub const HASHMAP_ENTRY_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"];
2729
pub const HASHMAP_PATH: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"];
2830
pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"];
2931
pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"];

tests/compile-fail/methods.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#![allow(unused)]
55
#![deny(clippy, clippy_pedantic)]
66

7+
use std::collections::BTreeMap;
8+
use std::collections::HashMap;
79
use std::ops::Mul;
810

911
struct T;
@@ -238,6 +240,18 @@ fn or_fun_call() {
238240
//~^ERROR use of `unwrap_or`
239241
//~|HELP try this
240242
//~|SUGGESTION without_default.unwrap_or_else(Foo::new);
243+
244+
let mut map = HashMap::<u64, String>::new();
245+
map.entry(42).or_insert(String::new());
246+
//~^ERROR use of `or_insert` followed by a function call
247+
//~|HELP try this
248+
//~|SUGGESTION map.entry(42).or_insert_with(String::new);
249+
250+
let mut btree = BTreeMap::<u64, String>::new();
251+
btree.entry(42).or_insert(String::new());
252+
//~^ERROR use of `or_insert` followed by a function call
253+
//~|HELP try this
254+
//~|SUGGESTION btree.entry(42).or_insert_with(String::new);
241255
}
242256

243257
fn main() {

0 commit comments

Comments
 (0)