Skip to content

Commit cf1e83b

Browse files
committed
Merged #365
2 parents 949c354 + b48db27 commit cf1e83b

File tree

5 files changed

+146
-8
lines changed

5 files changed

+146
-8
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code.
66
[Jump to usage instructions](#usage)
77

88
##Lints
9-
There are 62 lints included in this crate:
9+
There are 64 lints included in this crate:
1010

1111
name | default | meaning
1212
-------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -38,6 +38,8 @@ name
3838
[min_max](https://github.com/Manishearth/rust-clippy/wiki#min_max) | warn | `min(_, max(_, _))` (or vice versa) with bounds clamping the result to a constant
3939
[modulo_one](https://github.com/Manishearth/rust-clippy/wiki#modulo_one) | warn | taking a number modulo 1, which always returns 0
4040
[mut_mut](https://github.com/Manishearth/rust-clippy/wiki#mut_mut) | allow | usage of double-mut refs, e.g. `&mut &mut ...` (either copy'n'paste error, or shows a fundamental misunderstanding of references)
41+
[mutex_atomic](https://github.com/Manishearth/rust-clippy/wiki#mutex_atomic) | warn | using a Mutex where an atomic value could be used instead
42+
[mutex_integer](https://github.com/Manishearth/rust-clippy/wiki#mutex_integer) | allow | using a Mutex for an integer type
4143
[needless_bool](https://github.com/Manishearth/rust-clippy/wiki#needless_bool) | warn | if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }`
4244
[needless_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#needless_lifetimes) | warn | using explicit lifetimes for references in function arguments when elision rules would allow omitting them
4345
[needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub mod loops;
4747
pub mod ranges;
4848
pub mod matches;
4949
pub mod precedence;
50+
pub mod mutex_atomic;
5051
pub mod zero_div_zero;
5152
pub mod open_options;
5253

@@ -92,12 +93,14 @@ pub fn plugin_registrar(reg: &mut Registry) {
9293
reg.register_late_lint_pass(box minmax::MinMaxPass);
9394
reg.register_late_lint_pass(box open_options::NonSensicalOpenOptions);
9495
reg.register_late_lint_pass(box zero_div_zero::ZeroDivZeroPass);
96+
reg.register_late_lint_pass(box mutex_atomic::MutexAtomic);
9597

9698
reg.register_lint_group("clippy_pedantic", vec![
9799
methods::OPTION_UNWRAP_USED,
98100
methods::RESULT_UNWRAP_USED,
99101
methods::WRONG_PUB_SELF_CONVENTION,
100102
mut_mut::MUT_MUT,
103+
mutex_atomic::MUTEX_INTEGER,
101104
ptr_arg::PTR_ARG,
102105
shadow::SHADOW_REUSE,
103106
shadow::SHADOW_SAME,
@@ -146,6 +149,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
146149
misc::REDUNDANT_PATTERN,
147150
misc::TOPLEVEL_REF_ARG,
148151
mut_reference::UNNECESSARY_MUT_PASSED,
152+
mutex_atomic::MUTEX_ATOMIC,
149153
needless_bool::NEEDLESS_BOOL,
150154
open_options::NONSENSICAL_OPEN_OPTIONS,
151155
precedence::PRECEDENCE,

src/mutex_atomic.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//! Checks for uses of Mutex where an atomic value could be used
2+
//!
3+
//! This lint is **warn** by default
4+
5+
use rustc::lint::{LintPass, LintArray, LateLintPass, LateContext};
6+
use rustc_front::hir::Expr;
7+
8+
use syntax::ast;
9+
use rustc::middle::ty;
10+
use rustc::middle::subst::ParamSpace;
11+
12+
use utils::{span_lint, MUTEX_PATH, match_type};
13+
14+
declare_lint! {
15+
pub MUTEX_ATOMIC,
16+
Warn,
17+
"using a Mutex where an atomic value could be used instead"
18+
}
19+
20+
declare_lint! {
21+
pub MUTEX_INTEGER,
22+
Allow,
23+
"using a Mutex for an integer type"
24+
}
25+
26+
impl LintPass for MutexAtomic {
27+
fn get_lints(&self) -> LintArray {
28+
lint_array!(MUTEX_ATOMIC, MUTEX_INTEGER)
29+
}
30+
}
31+
32+
pub struct MutexAtomic;
33+
34+
impl LateLintPass for MutexAtomic {
35+
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
36+
let ty = cx.tcx.expr_ty(expr);
37+
if let &ty::TyStruct(_, subst) = &ty.sty {
38+
if match_type(cx, ty, &MUTEX_PATH) {
39+
let mutex_param = &subst.types.get(ParamSpace::TypeSpace, 0).sty;
40+
if let Some(atomic_name) = get_atomic_name(mutex_param) {
41+
let msg = format!("Consider using an {} instead of a \
42+
Mutex here. If you just want the \
43+
locking behaviour and not the internal \
44+
type, consider using Mutex<()>.",
45+
atomic_name);
46+
match *mutex_param {
47+
ty::TyUint(t) if t != ast::TyUs =>
48+
span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
49+
ty::TyInt(t) if t != ast::TyIs =>
50+
span_lint(cx, MUTEX_INTEGER, expr.span, &msg),
51+
_ => span_lint(cx, MUTEX_ATOMIC, expr.span, &msg)
52+
}
53+
}
54+
}
55+
}
56+
}
57+
}
58+
59+
fn get_atomic_name(ty: &ty::TypeVariants) -> Option<(&'static str)> {
60+
match *ty {
61+
ty::TyBool => Some("AtomicBool"),
62+
ty::TyUint(_) => Some("AtomicUsize"),
63+
ty::TyInt(_) => Some("AtomicIsize"),
64+
ty::TyRawPtr(_) => Some("AtomicPtr"),
65+
_ => None
66+
}
67+
}

src/utils.rs

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ use syntax::ast::Lit_::*;
1010
use syntax::ast;
1111

1212
// module DefPaths for certain structs/enums we check for
13-
pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"];
14-
pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"];
15-
pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"];
16-
pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"];
17-
pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"];
13+
pub const OPTION_PATH: [&'static str; 3] = ["core", "option", "Option"];
14+
pub const RESULT_PATH: [&'static str; 3] = ["core", "result", "Result"];
15+
pub const STRING_PATH: [&'static str; 3] = ["collections", "string", "String"];
16+
pub const VEC_PATH: [&'static str; 3] = ["collections", "vec", "Vec"];
17+
pub const LL_PATH: [&'static str; 3] = ["collections", "linked_list", "LinkedList"];
1818
pub const OPEN_OPTIONS_PATH: [&'static str; 3] = ["std", "fs", "OpenOptions"];
19+
pub const MUTEX_PATH: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"];
1920

2021
/// Produce a nested chain of if-lets and ifs from the patterns:
2122
///
@@ -78,8 +79,8 @@ pub fn in_external_macro<T: LintContext>(cx: &T, span: Span) -> bool {
7879
// no ExpnInfo = no macro
7980
opt_info.map_or(false, |info| {
8081
if let ExpnFormat::MacroAttribute(..) = info.callee.format {
81-
// these are all plugins
82-
return true;
82+
// these are all plugins
83+
return true;
8384
}
8485
// no span for the callee = external macro
8586
info.callee.span.map_or(true, |span| {
@@ -322,3 +323,49 @@ pub fn is_integer_literal(expr: &Expr, value: u64) -> bool
322323
}
323324
false
324325
}
326+
327+
/// Produce a nested chain of if-lets and ifs from the patterns:
328+
///
329+
/// if_let_chain! {
330+
/// [
331+
/// Some(y) = x,
332+
/// y.len() == 2,
333+
/// Some(z) = y,
334+
/// ],
335+
/// {
336+
/// block
337+
/// }
338+
/// }
339+
///
340+
/// becomes
341+
///
342+
/// if let Some(y) = x {
343+
/// if y.len() == 2 {
344+
/// if let Some(z) = y {
345+
/// block
346+
/// }
347+
/// }
348+
/// }
349+
#[macro_export]
350+
macro_rules! if_let_chain {
351+
([let $pat:pat = $expr:expr, $($tt:tt)+], $block:block) => {
352+
if let $pat = $expr {
353+
if_let_chain!{ [$($tt)+], $block }
354+
}
355+
};
356+
([let $pat:pat = $expr:expr], $block:block) => {
357+
if let $pat = $expr {
358+
$block
359+
}
360+
};
361+
([$expr:expr, $($tt:tt)+], $block:block) => {
362+
if $expr {
363+
if_let_chain!{ [$($tt)+], $block }
364+
}
365+
};
366+
([$expr:expr], $block:block) => {
367+
if $expr {
368+
$block
369+
}
370+
};
371+
}

tests/compile-fail/mutex_atomic.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#![feature(plugin)]
2+
3+
#![plugin(clippy)]
4+
#![deny(clippy)]
5+
#![deny(mutex_integer)]
6+
7+
fn main() {
8+
use std::sync::Mutex;
9+
Mutex::new(true); //~ERROR Consider using an AtomicBool instead of a Mutex here.
10+
Mutex::new(5usize); //~ERROR Consider using an AtomicUsize instead of a Mutex here.
11+
Mutex::new(9isize); //~ERROR Consider using an AtomicIsize instead of a Mutex here.
12+
let mut x = 4u32;
13+
Mutex::new(&x as *const u32); //~ERROR Consider using an AtomicPtr instead of a Mutex here.
14+
Mutex::new(&mut x as *mut u32); //~ERROR Consider using an AtomicPtr instead of a Mutex here.
15+
Mutex::new(0u32); //~ERROR Consider using an AtomicUsize instead of a Mutex here.
16+
Mutex::new(0i32); //~ERROR Consider using an AtomicIsize instead of a Mutex here.
17+
Mutex::new(0f32); // there are no float atomics, so this should not lint
18+
}

0 commit comments

Comments
 (0)