Skip to content

Commit d04bf15

Browse files
author
Michael Wright
committed
Merge branch 'master' into unneeded_wildcard_pattern
2 parents fed1709 + d07d001 commit d04bf15

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1246
-389
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,12 +1050,14 @@ Released 2018-09-13
10501050
[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum
10511051
[`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget
10521052
[`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none
1053+
[`mem_replace_with_uninit`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_uninit
10531054
[`min_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_max
10541055
[`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute
10551056
[`misrefactored_assign_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#misrefactored_assign_op
10561057
[`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn
10571058
[`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
10581059
[`missing_inline_in_public_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_inline_in_public_items
1060+
[`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc
10591061
[`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes
10601062
[`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals
10611063
[`module_inception`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_inception

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
88

9-
[There are 314 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
9+
[There are 316 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
1010

1111
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
1212

clippy_lints/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ semver = "0.9.0"
2727
serde = { version = "1.0", features = ["derive"] }
2828
toml = "0.5.3"
2929
unicode-normalization = "0.1"
30-
pulldown-cmark = "0.5.3"
30+
pulldown-cmark = "0.6.0"
3131
url = { version = "2.1.0", features = ["serde"] } # cargo requires serde feat in its url dep
3232
# see https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864
3333
if_chain = "1.0.0"

clippy_lints/src/assign_ops.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,13 +216,13 @@ fn lint_misrefactored_assign_op(
216216
long
217217
),
218218
format!("{} {}= {}", snip_a, op.node.as_str(), snip_r),
219-
Applicability::MachineApplicable,
219+
Applicability::MaybeIncorrect,
220220
);
221221
db.span_suggestion(
222222
expr.span,
223223
"or",
224224
long,
225-
Applicability::MachineApplicable, // snippet
225+
Applicability::MaybeIncorrect, // snippet
226226
);
227227
}
228228
},

clippy_lints/src/doc.rs

Lines changed: 83 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,40 @@ declare_clippy_lint! {
3434
"presence of `_`, `::` or camel-case outside backticks in documentation"
3535
}
3636

37+
declare_clippy_lint! {
38+
/// **What it does:** Checks for the doc comments of publicly visible
39+
/// unsafe functions and warns if there is no `# Safety` section.
40+
///
41+
/// **Why is this bad?** Unsafe functions should document their safety
42+
/// preconditions, so that users can be sure they are using them safely.
43+
///
44+
/// **Known problems:** None.
45+
///
46+
/// **Examples**:
47+
/// ```rust
48+
///# type Universe = ();
49+
/// /// This function should really be documented
50+
/// pub unsafe fn start_apocalypse(u: &mut Universe) {
51+
/// unimplemented!();
52+
/// }
53+
/// ```
54+
///
55+
/// At least write a line about safety:
56+
///
57+
/// ```rust
58+
///# type Universe = ();
59+
/// /// # Safety
60+
/// ///
61+
/// /// This function should not be called before the horsemen are ready.
62+
/// pub unsafe fn start_apocalypse(u: &mut Universe) {
63+
/// unimplemented!();
64+
/// }
65+
/// ```
66+
pub MISSING_SAFETY_DOC,
67+
style,
68+
"`pub unsafe fn` without `# Safety` docs"
69+
}
70+
3771
#[allow(clippy::module_name_repetitions)]
3872
#[derive(Clone)]
3973
pub struct DocMarkdown {
@@ -46,15 +80,28 @@ impl DocMarkdown {
4680
}
4781
}
4882

49-
impl_lint_pass!(DocMarkdown => [DOC_MARKDOWN]);
83+
impl_lint_pass!(DocMarkdown => [DOC_MARKDOWN, MISSING_SAFETY_DOC]);
5084

5185
impl EarlyLintPass for DocMarkdown {
5286
fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
5387
check_attrs(cx, &self.valid_idents, &krate.attrs);
5488
}
5589

5690
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
57-
check_attrs(cx, &self.valid_idents, &item.attrs);
91+
if check_attrs(cx, &self.valid_idents, &item.attrs) {
92+
return;
93+
}
94+
// no safety header
95+
if let ast::ItemKind::Fn(_, ref header, ..) = item.node {
96+
if item.vis.node.is_pub() && header.unsafety == ast::Unsafety::Unsafe {
97+
span_lint(
98+
cx,
99+
MISSING_SAFETY_DOC,
100+
item.span,
101+
"unsafe function's docs miss `# Safety` section",
102+
);
103+
}
104+
}
58105
}
59106
}
60107

@@ -115,7 +162,7 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(
115162
panic!("not a doc-comment: {}", comment);
116163
}
117164

118-
pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, attrs: &'a [ast::Attribute]) {
165+
pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, attrs: &'a [ast::Attribute]) -> bool {
119166
let mut doc = String::new();
120167
let mut spans = vec![];
121168

@@ -129,7 +176,7 @@ pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>,
129176
}
130177
} else if attr.check_name(sym!(doc)) {
131178
// ignore mix of sugared and non-sugared doc
132-
return;
179+
return true; // don't trigger the safety check
133180
}
134181
}
135182

@@ -140,57 +187,64 @@ pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>,
140187
current += offset_copy;
141188
}
142189

143-
if !doc.is_empty() {
144-
let parser = pulldown_cmark::Parser::new(&doc).into_offset_iter();
145-
// Iterate over all `Events` and combine consecutive events into one
146-
let events = parser.coalesce(|previous, current| {
147-
use pulldown_cmark::Event::*;
148-
149-
let previous_range = previous.1;
150-
let current_range = current.1;
151-
152-
match (previous.0, current.0) {
153-
(Text(previous), Text(current)) => {
154-
let mut previous = previous.to_string();
155-
previous.push_str(&current);
156-
Ok((Text(previous.into()), previous_range))
157-
},
158-
(previous, current) => Err(((previous, previous_range), (current, current_range))),
159-
}
160-
});
161-
check_doc(cx, valid_idents, events, &spans);
190+
if doc.is_empty() {
191+
return false;
162192
}
193+
194+
let parser = pulldown_cmark::Parser::new(&doc).into_offset_iter();
195+
// Iterate over all `Events` and combine consecutive events into one
196+
let events = parser.coalesce(|previous, current| {
197+
use pulldown_cmark::Event::*;
198+
199+
let previous_range = previous.1;
200+
let current_range = current.1;
201+
202+
match (previous.0, current.0) {
203+
(Text(previous), Text(current)) => {
204+
let mut previous = previous.to_string();
205+
previous.push_str(&current);
206+
Ok((Text(previous.into()), previous_range))
207+
},
208+
(previous, current) => Err(((previous, previous_range), (current, current_range))),
209+
}
210+
});
211+
check_doc(cx, valid_idents, events, &spans)
163212
}
164213

165214
fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize>)>>(
166215
cx: &EarlyContext<'_>,
167216
valid_idents: &FxHashSet<String>,
168217
events: Events,
169218
spans: &[(usize, Span)],
170-
) {
219+
) -> bool {
220+
// true if a safety header was found
171221
use pulldown_cmark::Event::*;
172222
use pulldown_cmark::Tag::*;
173223

224+
let mut safety_header = false;
174225
let mut in_code = false;
175226
let mut in_link = None;
227+
let mut in_heading = false;
176228

177229
for (event, range) in events {
178230
match event {
179231
Start(CodeBlock(_)) => in_code = true,
180232
End(CodeBlock(_)) => in_code = false,
181233
Start(Link(_, url, _)) => in_link = Some(url),
182234
End(Link(..)) => in_link = None,
183-
Start(_tag) | End(_tag) => (), // We don't care about other tags
184-
Html(_html) | InlineHtml(_html) => (), // HTML is weird, just ignore it
185-
SoftBreak | HardBreak | TaskListMarker(_) | Code(_) => (),
235+
Start(Heading(_)) => in_heading = true,
236+
End(Heading(_)) => in_heading = false,
237+
Start(_tag) | End(_tag) => (), // We don't care about other tags
238+
Html(_html) => (), // HTML is weird, just ignore it
239+
SoftBreak | HardBreak | TaskListMarker(_) | Code(_) | Rule => (),
186240
FootnoteReference(text) | Text(text) => {
187241
if Some(&text) == in_link.as_ref() {
188242
// Probably a link of the form `<http://example.com>`
189243
// Which are represented as a link to "http://example.com" with
190244
// text "http://example.com" by pulldown-cmark
191245
continue;
192246
}
193-
247+
safety_header |= in_heading && text.trim() == "Safety";
194248
if !in_code {
195249
let index = match spans.binary_search_by(|c| c.0.cmp(&range.start)) {
196250
Ok(o) => o,
@@ -207,6 +261,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
207261
},
208262
}
209263
}
264+
safety_header
210265
}
211266

212267
fn check_text(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) {

clippy_lints/src/drop_forget_ref.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::utils::{is_copy, match_def_path, paths, span_note_and_lint};
1+
use crate::utils::{is_copy, match_def_path, paths, qpath_res, span_note_and_lint};
22
use if_chain::if_chain;
33
use rustc::hir::*;
44
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
@@ -114,7 +114,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DropForgetRef {
114114
if let ExprKind::Call(ref path, ref args) = expr.node;
115115
if let ExprKind::Path(ref qpath) = path.node;
116116
if args.len() == 1;
117-
if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id();
117+
if let Some(def_id) = qpath_res(cx, qpath, path.hir_id).opt_def_id();
118118
then {
119119
let lint;
120120
let msg;

clippy_lints/src/explicit_write.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ fn write_output_string(write_args: &HirVec<Expr>) -> Option<String> {
140140
if output_args.len() > 0;
141141
if let ExprKind::AddrOf(_, ref output_string_expr) = output_args[0].node;
142142
if let ExprKind::Array(ref string_exprs) = output_string_expr.node;
143-
if string_exprs.len() > 0;
143+
// we only want to provide an automatic suggestion for simple (non-format) strings
144+
if string_exprs.len() == 1;
144145
if let ExprKind::Lit(ref lit) = string_exprs[0].node;
145146
if let LitKind::Str(ref write_output, _) = lit.node;
146147
then {

clippy_lints/src/functions.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::convert::TryFrom;
22

3-
use crate::utils::{iter_input_pats, snippet, snippet_opt, span_lint, type_is_unsafe_function};
3+
use crate::utils::{iter_input_pats, qpath_res, snippet, snippet_opt, span_lint, type_is_unsafe_function};
44
use matches::matches;
55
use rustc::hir;
66
use rustc::hir::def::Res;
@@ -318,7 +318,7 @@ impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
318318
impl<'a, 'tcx> DerefVisitor<'a, 'tcx> {
319319
fn check_arg(&self, ptr: &hir::Expr) {
320320
if let hir::ExprKind::Path(ref qpath) = ptr.node {
321-
if let Res::Local(id) = self.cx.tables.qpath_res(qpath, ptr.hir_id) {
321+
if let Res::Local(id) = qpath_res(self.cx, qpath, ptr.hir_id) {
322322
if self.ptrs.contains(&id) {
323323
span_lint(
324324
self.cx,

clippy_lints/src/let_if_seq.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::utils::{higher, snippet, span_lint_and_then};
1+
use crate::utils::{higher, qpath_res, snippet, span_lint_and_then};
22
use if_chain::if_chain;
33
use rustc::hir;
44
use rustc::hir::def::Res;
@@ -145,7 +145,7 @@ impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for UsedVisitor<'a, 'tcx> {
145145
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
146146
if_chain! {
147147
if let hir::ExprKind::Path(ref qpath) = expr.node;
148-
if let Res::Local(local_id) = self.cx.tables.qpath_res(qpath, expr.hir_id);
148+
if let Res::Local(local_id) = qpath_res(self.cx, qpath, expr.hir_id);
149149
if self.id == local_id;
150150
then {
151151
self.used = true;
@@ -170,7 +170,7 @@ fn check_assign<'a, 'tcx>(
170170
if let hir::StmtKind::Semi(ref expr) = expr.node;
171171
if let hir::ExprKind::Assign(ref var, ref value) = expr.node;
172172
if let hir::ExprKind::Path(ref qpath) = var.node;
173-
if let Res::Local(local_id) = cx.tables.qpath_res(qpath, var.hir_id);
173+
if let Res::Local(local_id) = qpath_res(cx, qpath, var.hir_id);
174174
if decl == local_id;
175175
then {
176176
let mut v = UsedVisitor {

clippy_lints/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
667667
shadow::SHADOW_UNRELATED,
668668
strings::STRING_ADD_ASSIGN,
669669
trait_bounds::TYPE_REPETITION_IN_BOUNDS,
670+
types::CAST_LOSSLESS,
670671
types::CAST_POSSIBLE_TRUNCATION,
671672
types::CAST_POSSIBLE_WRAP,
672673
types::CAST_PRECISION_LOSS,
@@ -708,6 +709,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
708709
copies::IFS_SAME_COND,
709710
copies::IF_SAME_THEN_ELSE,
710711
derive::DERIVE_HASH_XOR_EQ,
712+
doc::MISSING_SAFETY_DOC,
711713
double_comparison::DOUBLE_COMPARISONS,
712714
double_parens::DOUBLE_PARENS,
713715
drop_bounds::DROP_BOUNDS,
@@ -781,6 +783,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
781783
matches::SINGLE_MATCH,
782784
mem_discriminant::MEM_DISCRIMINANT_NON_ENUM,
783785
mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
786+
mem_replace::MEM_REPLACE_WITH_UNINIT,
784787
methods::CHARS_LAST_CMP,
785788
methods::CHARS_NEXT_CMP,
786789
methods::CLONE_DOUBLE_REF,
@@ -891,7 +894,6 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
891894
types::ABSURD_EXTREME_COMPARISONS,
892895
types::BORROWED_BOX,
893896
types::BOX_VEC,
894-
types::CAST_LOSSLESS,
895897
types::CAST_PTR_ALIGNMENT,
896898
types::CAST_REF_TO_MUT,
897899
types::CHAR_LIT_AS_U8,
@@ -930,6 +932,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
930932
block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR,
931933
block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT,
932934
collapsible_if::COLLAPSIBLE_IF,
935+
doc::MISSING_SAFETY_DOC,
933936
enum_variants::ENUM_VARIANT_NAMES,
934937
enum_variants::MODULE_INCEPTION,
935938
eq_op::OP_REF,
@@ -1074,7 +1077,6 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
10741077
transmute::TRANSMUTE_PTR_TO_REF,
10751078
transmute::USELESS_TRANSMUTE,
10761079
types::BORROWED_BOX,
1077-
types::CAST_LOSSLESS,
10781080
types::CHAR_LIT_AS_U8,
10791081
types::OPTION_OPTION,
10801082
types::TYPE_COMPLEXITY,
@@ -1118,6 +1120,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
11181120
loops::REVERSE_RANGE_LOOP,
11191121
loops::WHILE_IMMUTABLE_CONDITION,
11201122
mem_discriminant::MEM_DISCRIMINANT_NON_ENUM,
1123+
mem_replace::MEM_REPLACE_WITH_UNINIT,
11211124
methods::CLONE_DOUBLE_REF,
11221125
methods::INTO_ITER_ON_ARRAY,
11231126
methods::TEMPORARY_CSTRING_AS_PTR,

0 commit comments

Comments
 (0)