Skip to content

Commit 7778f31

Browse files
committed
Merge branch 'master' into sugg
2 parents 2f259b8 + 5d6e4a6 commit 7778f31

File tree

11 files changed

+237
-38
lines changed

11 files changed

+237
-38
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Change Log
22
All notable changes to this project will be documented in this file.
33

4-
## 0.0.78 - TBA
4+
## 0.0.78 - 2016-07-02
5+
* Rustup to *rustc 1.11.0-nightly (01411937f 2016-07-01)*
56
* New lints: [`wrong_transmute`, `double_neg`]
67
* For compatibility, `cargo clippy` does not defines the `clippy` feature
78
introduced in 0.0.76 anymore
@@ -14,6 +15,7 @@ All notable changes to this project will be documented in this file.
1415
## 0.0.76 — 2016-06-10
1516
* Rustup to *rustc 1.11.0-nightly (7d2f75a95 2016-06-09)*
1617
* `cargo clippy` now automatically defines the `clippy` feature
18+
* New lint: [`not_unsafe_ptr_arg_deref`]
1719

1820
## 0.0.75 — 2016-06-08
1921
* Rustup to *rustc 1.11.0-nightly (763f9234b 2016-06-06)*
@@ -219,6 +221,7 @@ All notable changes to this project will be documented in this file.
219221
[`non_ascii_literal`]: https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal
220222
[`nonminimal_bool`]: https://github.com/Manishearth/rust-clippy/wiki#nonminimal_bool
221223
[`nonsensical_open_options`]: https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options
224+
[`not_unsafe_ptr_arg_deref`]: https://github.com/Manishearth/rust-clippy/wiki#not_unsafe_ptr_arg_deref
222225
[`ok_expect`]: https://github.com/Manishearth/rust-clippy/wiki#ok_expect
223226
[`option_map_unwrap_or`]: https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or
224227
[`option_map_unwrap_or_else`]: https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "clippy"
3-
version = "0.0.77"
3+
version = "0.0.78"
44
authors = [
55
"Manish Goregaokar <manishsmail@gmail.com>",
66
"Andre Bogus <bogusandre@gmail.com>",
@@ -25,7 +25,7 @@ test = false
2525

2626
[dependencies]
2727
# begin automatic update
28-
clippy_lints = { version = "0.0.77", path = "clippy_lints" }
28+
clippy_lints = { version = "0.0.78", path = "clippy_lints" }
2929
# end automatic update
3030

3131
[dev-dependencies]

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Table of contents:
1717

1818
## Lints
1919

20-
There are 157 lints included in this crate:
20+
There are 158 lints included in this crate:
2121

2222
name | default | meaning
2323
---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -115,6 +115,7 @@ name
115115
[non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead
116116
[nonminimal_bool](https://github.com/Manishearth/rust-clippy/wiki#nonminimal_bool) | allow | checks for boolean expressions that can be written more concisely
117117
[nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file
118+
[not_unsafe_ptr_arg_deref](https://github.com/Manishearth/rust-clippy/wiki#not_unsafe_ptr_arg_deref) | warn | public functions dereferencing raw pointer arguments but not marked `unsafe`
118119
[ok_expect](https://github.com/Manishearth/rust-clippy/wiki#ok_expect) | warn | using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result
119120
[option_map_unwrap_or](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or) | warn | using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as `map_or(a, f)`
120121
[option_map_unwrap_or_else](https://github.com/Manishearth/rust-clippy/wiki#option_map_unwrap_or_else) | warn | using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`

clippy_lints/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "clippy_lints"
33
# begin automatic update
4-
version = "0.0.77"
4+
version = "0.0.78"
55
# end automatic update
66
authors = [
77
"Manish Goregaokar <manishsmail@gmail.com>",

clippy_lints/src/functions.rs

Lines changed: 124 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
use rustc::lint::*;
2-
use rustc::hir;
31
use rustc::hir::intravisit;
2+
use rustc::hir;
3+
use rustc::ty;
4+
use rustc::lint::*;
5+
use std::collections::HashSet;
46
use syntax::ast;
57
use syntax::codemap::Span;
6-
use utils::span_lint;
8+
use utils::{span_lint, type_is_unsafe_function};
79

810
/// **What it does:** Check for functions with too many parameters.
911
///
@@ -15,7 +17,7 @@ use utils::span_lint;
1517
///
1618
/// **Example:**
1719
///
18-
/// ```
20+
/// ```rust
1921
/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) { .. }
2022
/// ```
2123
declare_lint! {
@@ -24,6 +26,30 @@ declare_lint! {
2426
"functions with too many arguments"
2527
}
2628

29+
/// **What it does:** Check for public functions that dereferences raw pointer arguments but are
30+
/// not marked unsafe.
31+
///
32+
/// **Why is this bad?** The function should probably be marked `unsafe`, since for an arbitrary
33+
/// raw pointer, there is no way of telling for sure if it is valid.
34+
///
35+
/// **Known problems:**
36+
///
37+
/// * It does not check functions recursively so if the pointer is passed to a private non-
38+
/// `unsafe` function which does the dereferencing, the lint won't trigger.
39+
/// * It only checks for arguments whose type are raw pointers, not raw pointers got from an
40+
/// argument in some other way (`fn foo(bar: &[*const u8])` or `some_argument.get_raw_ptr()`).
41+
///
42+
/// **Example:**
43+
///
44+
/// ```rust
45+
/// pub fn foo(x: *const u8) { println!("{}", unsafe { *x }); }
46+
/// ```
47+
declare_lint! {
48+
pub NOT_UNSAFE_PTR_ARG_DEREF,
49+
Warn,
50+
"public functions dereferencing raw pointer arguments but not marked `unsafe`"
51+
}
52+
2753
#[derive(Copy,Clone)]
2854
pub struct Functions {
2955
threshold: u64,
@@ -37,29 +63,41 @@ impl Functions {
3763

3864
impl LintPass for Functions {
3965
fn get_lints(&self) -> LintArray {
40-
lint_array!(TOO_MANY_ARGUMENTS)
66+
lint_array!(TOO_MANY_ARGUMENTS, NOT_UNSAFE_PTR_ARG_DEREF)
4167
}
4268
}
4369

4470
impl LateLintPass for Functions {
45-
fn check_fn(&mut self, cx: &LateContext, _: intravisit::FnKind, decl: &hir::FnDecl, _: &hir::Block, span: Span,
46-
nodeid: ast::NodeId) {
71+
fn check_fn(&mut self, cx: &LateContext, kind: intravisit::FnKind, decl: &hir::FnDecl, block: &hir::Block, span: Span, nodeid: ast::NodeId) {
4772
use rustc::hir::map::Node::*;
4873

49-
if let Some(NodeItem(ref item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) {
50-
match item.node {
51-
hir::ItemImpl(_, _, _, Some(_), _, _) |
52-
hir::ItemDefaultImpl(..) => return,
53-
_ => (),
54-
}
74+
let is_impl = if let Some(NodeItem(ref item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) {
75+
matches!(item.node, hir::ItemImpl(_, _, _, Some(_), _, _) | hir::ItemDefaultImpl(..))
76+
} else {
77+
false
78+
};
79+
80+
let unsafety = match kind {
81+
hir::intravisit::FnKind::ItemFn(_, _, unsafety, _, _, _, _) => unsafety,
82+
hir::intravisit::FnKind::Method(_, sig, _, _) => sig.unsafety,
83+
hir::intravisit::FnKind::Closure(_) => return,
84+
};
85+
86+
// don't warn for implementations, it's not their fault
87+
if !is_impl {
88+
self.check_arg_number(cx, decl, span);
5589
}
5690

57-
self.check_arg_number(cx, decl, span);
91+
self.check_raw_ptr(cx, unsafety, decl, block, nodeid);
5892
}
5993

6094
fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
61-
if let hir::MethodTraitItem(ref sig, _) = item.node {
95+
if let hir::MethodTraitItem(ref sig, ref block) = item.node {
6296
self.check_arg_number(cx, &sig.decl, item.span);
97+
98+
if let Some(ref block) = *block {
99+
self.check_raw_ptr(cx, sig.unsafety, &sig.decl, block, item.id);
100+
}
63101
}
64102
}
65103
}
@@ -74,4 +112,75 @@ impl Functions {
74112
&format!("this function has too many arguments ({}/{})", args, self.threshold));
75113
}
76114
}
115+
116+
fn check_raw_ptr(&self, cx: &LateContext, unsafety: hir::Unsafety, decl: &hir::FnDecl, block: &hir::Block, nodeid: ast::NodeId) {
117+
if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(nodeid) {
118+
let raw_ptrs = decl.inputs.iter().filter_map(|arg| raw_ptr_arg(cx, arg)).collect::<HashSet<_>>();
119+
120+
if !raw_ptrs.is_empty() {
121+
let mut v = DerefVisitor {
122+
cx: cx,
123+
ptrs: raw_ptrs,
124+
};
125+
126+
hir::intravisit::walk_block(&mut v, block);
127+
}
128+
}
129+
}
130+
}
131+
132+
fn raw_ptr_arg(cx: &LateContext, arg: &hir::Arg) -> Option<hir::def_id::DefId> {
133+
if let (&hir::PatKind::Binding(_, _, _), &hir::TyPtr(_)) = (&arg.pat.node, &arg.ty.node) {
134+
cx.tcx.def_map.borrow().get(&arg.pat.id).map(|pr| pr.full_def().def_id())
135+
} else {
136+
None
137+
}
138+
}
139+
140+
struct DerefVisitor<'a, 'tcx: 'a> {
141+
cx: &'a LateContext<'a, 'tcx>,
142+
ptrs: HashSet<hir::def_id::DefId>,
143+
}
144+
145+
impl<'a, 'tcx, 'v> hir::intravisit::Visitor<'v> for DerefVisitor<'a, 'tcx> {
146+
fn visit_expr(&mut self, expr: &'v hir::Expr) {
147+
match expr.node {
148+
hir::ExprCall(ref f, ref args) => {
149+
let ty = self.cx.tcx.expr_ty(f);
150+
151+
if type_is_unsafe_function(ty) {
152+
for arg in args {
153+
self.check_arg(arg);
154+
}
155+
}
156+
}
157+
hir::ExprMethodCall(_, _, ref args) => {
158+
let method_call = ty::MethodCall::expr(expr.id);
159+
let base_type = self.cx.tcx.tables.borrow().method_map[&method_call].ty;
160+
161+
if type_is_unsafe_function(base_type) {
162+
for arg in args {
163+
self.check_arg(arg);
164+
}
165+
}
166+
}
167+
hir::ExprUnary(hir::UnDeref, ref ptr) => self.check_arg(ptr),
168+
_ => (),
169+
}
170+
171+
hir::intravisit::walk_expr(self, expr);
172+
}
173+
}
174+
175+
impl<'a, 'tcx: 'a> DerefVisitor<'a, 'tcx> {
176+
fn check_arg(&self, ptr: &hir::Expr) {
177+
if let Some(def) = self.cx.tcx.def_map.borrow().get(&ptr.id) {
178+
if self.ptrs.contains(&def.full_def().def_id()) {
179+
span_lint(self.cx,
180+
NOT_UNSAFE_PTR_ARG_DEREF,
181+
ptr.span,
182+
"this public function dereferences a raw pointer but is not marked `unsafe`");
183+
}
184+
}
185+
}
77186
}

clippy_lints/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
324324
format::USELESS_FORMAT,
325325
formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
326326
formatting::SUSPICIOUS_ELSE_FORMATTING,
327+
functions::NOT_UNSAFE_PTR_ARG_DEREF,
327328
functions::TOO_MANY_ARGUMENTS,
328329
identity_op::IDENTITY_OP,
329330
len_zero::LEN_WITHOUT_IS_EMPTY,

clippy_lints/src/methods.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ declare_lint! {
7373
/// |`is_` |`&self` or none |
7474
/// |`to_` |`&self` |
7575
///
76-
/// **Why is this bad?** Consistency breeds readability. If you follow the conventions, your users won't be surprised that they e.g. need to supply a mutable reference to a `as_..` function.
76+
/// **Why is this bad?** Consistency breeds readability. If you follow the conventions, your users won't be surprised that they, e.g., need to supply a mutable reference to a `as_..` function.
7777
///
7878
/// **Known problems:** None
7979
///

clippy_lints/src/utils/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,3 +714,12 @@ pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: ty::Ty<'tcx>, b: ty::Ty
714714
infcx.can_equate(&new_a, &new_b).is_ok()
715715
})
716716
}
717+
718+
/// Return whether the given type is an `unsafe` function.
719+
pub fn type_is_unsafe_function(ty: ty::Ty) -> bool {
720+
match ty.sty {
721+
ty::TyFnDef(_, _, ref f) |
722+
ty::TyFnPtr(ref f) => f.unsafety == Unsafety::Unsafe,
723+
_ => false,
724+
}
725+
}

clippy_lints/src/vec.rs

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use rustc::lint::*;
22
use rustc::ty::TypeVariants;
33
use rustc::hir::*;
4+
use rustc_const_eval::EvalHint::ExprTypeChecked;
5+
use rustc_const_eval::eval_const_expr_partial;
46
use syntax::codemap::Span;
57
use utils::{higher, snippet, span_lint_and_then};
68

@@ -51,26 +53,30 @@ impl LateLintPass for Pass {
5153

5254
fn check_vec_macro(cx: &LateContext, vec: &Expr, span: Span) {
5355
if let Some(vec_args) = higher::vec_macro(cx, vec) {
54-
span_lint_and_then(cx, USELESS_VEC, span, "useless use of `vec!`", |db| {
55-
let snippet = match vec_args {
56-
higher::VecArgs::Repeat(elem, len) => {
56+
let snippet = match vec_args {
57+
higher::VecArgs::Repeat(elem, len) => {
58+
if eval_const_expr_partial(cx.tcx, len, ExprTypeChecked, None).is_ok() {
5759
format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into()
60+
} else {
61+
return;
5862
}
59-
higher::VecArgs::Vec(args) => {
60-
if let Some(last) = args.iter().last() {
61-
let span = Span {
62-
lo: args[0].span.lo,
63-
hi: last.span.hi,
64-
expn_id: args[0].span.expn_id,
65-
};
63+
}
64+
higher::VecArgs::Vec(args) => {
65+
if let Some(last) = args.iter().last() {
66+
let span = Span {
67+
lo: args[0].span.lo,
68+
hi: last.span.hi,
69+
expn_id: args[0].span.expn_id,
70+
};
6671

67-
format!("&[{}]", snippet(cx, span, "..")).into()
68-
} else {
69-
"&[]".into()
70-
}
72+
format!("&[{}]", snippet(cx, span, "..")).into()
73+
} else {
74+
"&[]".into()
7175
}
72-
};
76+
}
77+
};
7378

79+
span_lint_and_then(cx, USELESS_VEC, span, "useless use of `vec!`", |db| {
7480
db.span_suggestion(span, "you can use a slice directly", snippet);
7581
});
7682
}

0 commit comments

Comments
 (0)