Skip to content

Commit b903d1c

Browse files
authored
Merge pull request #2797 from mipli/2250-unimplemented-macro
Lint for unimplemented!()
2 parents e7a3e03 + 1f10dd2 commit b903d1c

File tree

7 files changed

+130
-69
lines changed

7 files changed

+130
-69
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,7 @@ All notable changes to this project will be documented in this file.
815815
[`trivial_regex`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#trivial_regex
816816
[`type_complexity`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#type_complexity
817817
[`unicode_not_nfc`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unicode_not_nfc
818+
[`unimplemented`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unimplemented
818819
[`unit_arg`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unit_arg
819820
[`unit_cmp`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unit_cmp
820821
[`unnecessary_cast`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#unnecessary_cast

README.md

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

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

10-
[There are 258 lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)
10+
[There are 259 lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)
1111

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

clippy_lints/src/lib.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ pub mod non_expressive_names;
177177
pub mod ok_if_let;
178178
pub mod open_options;
179179
pub mod overflow_check_conditional;
180-
pub mod panic;
180+
pub mod panic_unimplemented;
181181
pub mod partialeq_ne_impl;
182182
pub mod precedence;
183183
pub mod ptr;
@@ -352,7 +352,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
352352
reg.register_late_lint_pass(box escape::Pass{too_large_for_stack: conf.too_large_for_stack});
353353
reg.register_early_lint_pass(box misc_early::MiscEarly);
354354
reg.register_late_lint_pass(box array_indexing::ArrayIndexing);
355-
reg.register_late_lint_pass(box panic::Pass);
355+
reg.register_late_lint_pass(box panic_unimplemented::Pass);
356356
reg.register_late_lint_pass(box strings::StringLitAsBytes);
357357
reg.register_late_lint_pass(box derive::Derive);
358358
reg.register_late_lint_pass(box types::CharLitAsU8);
@@ -434,6 +434,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
434434
methods::WRONG_PUB_SELF_CONVENTION,
435435
misc::FLOAT_CMP_CONST,
436436
missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
437+
panic_unimplemented::UNIMPLEMENTED,
437438
shadow::SHADOW_REUSE,
438439
shadow::SHADOW_SAME,
439440
shadow::SHADOW_UNRELATED,
@@ -626,7 +627,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
626627
ok_if_let::IF_LET_SOME_RESULT,
627628
open_options::NONSENSICAL_OPEN_OPTIONS,
628629
overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
629-
panic::PANIC_PARAMS,
630+
panic_unimplemented::PANIC_PARAMS,
630631
partialeq_ne_impl::PARTIALEQ_NE_IMPL,
631632
precedence::PRECEDENCE,
632633
ptr::CMP_NULL,
@@ -748,7 +749,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
748749
non_expressive_names::JUST_UNDERSCORES_AND_DIGITS,
749750
non_expressive_names::MANY_SINGLE_CHAR_NAMES,
750751
ok_if_let::IF_LET_SOME_RESULT,
751-
panic::PANIC_PARAMS,
752+
panic_unimplemented::PANIC_PARAMS,
752753
ptr::CMP_NULL,
753754
ptr::PTR_ARG,
754755
question_mark::QUESTION_MARK,

clippy_lints/src/panic.rs

Lines changed: 0 additions & 58 deletions
This file was deleted.
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use rustc::hir::*;
2+
use rustc::lint::*;
3+
use syntax::ast::LitKind;
4+
use syntax::ptr::P;
5+
use syntax::ext::quote::rt::Span;
6+
use utils::{is_direct_expn_of, is_expn_of, match_def_path, opt_def_id, paths, resolve_node, span_lint};
7+
8+
/// **What it does:** Checks for missing parameters in `panic!`.
9+
///
10+
/// **Why is this bad?** Contrary to the `format!` family of macros, there are
11+
/// two forms of `panic!`: if there are no parameters given, the first argument
12+
/// is not a format string and used literally. So while `format!("{}")` will
13+
/// fail to compile, `panic!("{}")` will not.
14+
///
15+
/// **Known problems:** None.
16+
///
17+
/// **Example:**
18+
/// ```rust
19+
/// panic!("This `panic!` is probably missing a parameter there: {}");
20+
/// ```
21+
declare_clippy_lint! {
22+
pub PANIC_PARAMS,
23+
style,
24+
"missing parameters in `panic!` calls"
25+
}
26+
27+
/// **What it does:** Checks for usage of `unimplemented!`.
28+
///
29+
/// **Why is this bad?** This macro should not be present in production code
30+
///
31+
/// **Known problems:** None.
32+
///
33+
/// **Example:**
34+
/// ```rust
35+
/// unimplemented!();
36+
/// ```
37+
declare_clippy_lint! {
38+
pub UNIMPLEMENTED,
39+
restriction,
40+
"`unimplemented!` should not be present in production code"
41+
}
42+
43+
#[allow(missing_copy_implementations)]
44+
pub struct Pass;
45+
46+
impl LintPass for Pass {
47+
fn get_lints(&self) -> LintArray {
48+
lint_array!(PANIC_PARAMS, UNIMPLEMENTED)
49+
}
50+
}
51+
52+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
53+
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
54+
if_chain! {
55+
if let ExprBlock(ref block, _) = expr.node;
56+
if let Some(ref ex) = block.expr;
57+
if let ExprCall(ref fun, ref params) = ex.node;
58+
if let ExprPath(ref qpath) = fun.node;
59+
if let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id));
60+
if match_def_path(cx.tcx, fun_def_id, &paths::BEGIN_PANIC);
61+
if params.len() == 2;
62+
then {
63+
if is_expn_of(expr.span, "unimplemented").is_some() {
64+
let span = get_outer_span(expr);
65+
span_lint(cx, UNIMPLEMENTED, span,
66+
"`unimplemented` should not be present in production code");
67+
} else {
68+
match_panic(params, expr, cx);
69+
}
70+
}
71+
}
72+
}
73+
}
74+
75+
fn get_outer_span(expr: &Expr) -> Span {
76+
if_chain! {
77+
if let Some(first) = expr.span.ctxt().outer().expn_info();
78+
if let Some(second) = first.call_site.ctxt().outer().expn_info();
79+
then {
80+
second.call_site
81+
} else {
82+
expr.span
83+
}
84+
}
85+
}
86+
87+
fn match_panic(params: &P<[Expr]>, expr: &Expr, cx: &LateContext) {
88+
if_chain! {
89+
if let ExprLit(ref lit) = params[0].node;
90+
if is_direct_expn_of(expr.span, "panic").is_some();
91+
if let LitKind::Str(ref string, _) = lit.node;
92+
let string = string.as_str().replace("{{", "").replace("}}", "");
93+
if let Some(par) = string.find('{');
94+
if string[par..].contains('}');
95+
if params[0].span.source_callee().is_none();
96+
if params[0].span.lo() != params[0].span.hi();
97+
then {
98+
span_lint(cx, PANIC_PARAMS, params[0].span,
99+
"you probably are missing some parameter in your format string");
100+
}
101+
}
102+
}

tests/ui/panic.rs renamed to tests/ui/panic_unimplemented.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22

33

4-
#![warn(panic_params)]
4+
#![warn(panic_params, unimplemented)]
55

66
fn missing() {
77
if true {
@@ -53,6 +53,12 @@ fn ok_escaped() {
5353
panic!("{case }}");
5454
}
5555

56+
fn unimplemented() {
57+
let a = 2;
58+
unimplemented!();
59+
let b = a + 2;
60+
}
61+
5662
fn main() {
5763
missing();
5864
ok_single();
@@ -61,4 +67,5 @@ fn main() {
6167
ok_inner();
6268
ok_nomsg();
6369
ok_escaped();
70+
unimplemented();
6471
}
Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,36 @@
11
error: you probably are missing some parameter in your format string
2-
--> $DIR/panic.rs:8:16
2+
--> $DIR/panic_unimplemented.rs:8:16
33
|
44
8 | panic!("{}");
55
| ^^^^
66
|
77
= note: `-D panic-params` implied by `-D warnings`
88

99
error: you probably are missing some parameter in your format string
10-
--> $DIR/panic.rs:10:16
10+
--> $DIR/panic_unimplemented.rs:10:16
1111
|
1212
10 | panic!("{:?}");
1313
| ^^^^^^
1414

1515
error: you probably are missing some parameter in your format string
16-
--> $DIR/panic.rs:12:23
16+
--> $DIR/panic_unimplemented.rs:12:23
1717
|
1818
12 | assert!(true, "here be missing values: {}");
1919
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2020

2121
error: you probably are missing some parameter in your format string
22-
--> $DIR/panic.rs:15:12
22+
--> $DIR/panic_unimplemented.rs:15:12
2323
|
2424
15 | panic!("{{{this}}}");
2525
| ^^^^^^^^^^^^
2626

27-
error: aborting due to 4 previous errors
27+
error: `unimplemented` should not be present in production code
28+
--> $DIR/panic_unimplemented.rs:58:5
29+
|
30+
58 | unimplemented!();
31+
| ^^^^^^^^^^^^^^^^^
32+
|
33+
= note: `-D unimplemented` implied by `-D warnings`
34+
35+
error: aborting due to 5 previous errors
2836

0 commit comments

Comments
 (0)