Skip to content

Commit 1479c18

Browse files
author
Frank
committed
add disallowed_method lint
1 parent cc1998f commit 1479c18

File tree

10 files changed

+199
-0
lines changed

10 files changed

+199
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,7 @@ Released 2018-09-13
15591559
[`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof
15601560
[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
15611561
[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
1562+
[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
15621563
[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
15631564
[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
15641565
[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons

clippy_lints/src/disallowed_method.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use crate::utils::span_lint;
2+
3+
use rustc_data_structures::fx::FxHashSet;
4+
use rustc_lint::{LateLintPass, LateContext};
5+
use rustc_session::{impl_lint_pass, declare_tool_lint};
6+
use rustc_hir::*;
7+
use rustc_span::Symbol;
8+
9+
declare_clippy_lint! {
10+
/// **What it does:** Lints for specific trait methods defined in clippy.toml
11+
///
12+
/// **Why is this bad?** Some methods are undesirable in certain contexts,
13+
/// and it would be beneficial to lint for them as needed.
14+
///
15+
/// **Known problems:** None.
16+
///
17+
/// **Example:**
18+
///
19+
/// ```rust
20+
/// // example code where clippy issues a warning
21+
/// foo.bad_method(); // Foo is disallowed
22+
/// ```
23+
/// Use instead:
24+
/// ```rust
25+
/// // example code which does not raise clippy warning
26+
/// GoodStruct.bad_method(); // not disallowed
27+
/// ```
28+
pub DISALLOWED_METHOD,
29+
nursery,
30+
"used disallowed method call"
31+
}
32+
33+
#[derive(Clone, Debug)]
34+
pub struct DisallowedMethod {
35+
disallowed: FxHashSet<Vec<Symbol>>,
36+
}
37+
38+
impl DisallowedMethod {
39+
pub fn new(disallowed: FxHashSet<String>) -> Self {
40+
Self {
41+
disallowed: disallowed.iter()
42+
.map(|s| {
43+
s.split("::").map(|seg| Symbol::intern(seg)).collect::<Vec<_>>()
44+
})
45+
.collect(),
46+
}
47+
}
48+
}
49+
50+
impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]);
51+
52+
impl <'tcx> LateLintPass<'tcx> for DisallowedMethod {
53+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
54+
if let ExprKind::MethodCall(path, _, _args, _) = &expr.kind {
55+
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
56+
57+
let method_call = cx.get_def_path(def_id);
58+
if self.disallowed.contains(&method_call) {
59+
span_lint(
60+
cx,
61+
DISALLOWED_METHOD,
62+
expr.span,
63+
&format!(
64+
"Use of a disallowed method `{}`",
65+
method_call
66+
.iter()
67+
.map(|s| s.to_ident_string())
68+
.collect::<Vec<_>>()
69+
.join("::"),
70+
)
71+
);
72+
}
73+
}
74+
}
75+
}

clippy_lints/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ mod dbg_macro;
175175
mod default_trait_access;
176176
mod dereference;
177177
mod derive;
178+
mod disallowed_method;
178179
mod doc;
179180
mod double_comparison;
180181
mod double_parens;
@@ -525,6 +526,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
525526
&derive::DERIVE_ORD_XOR_PARTIAL_ORD,
526527
&derive::EXPL_IMPL_CLONE_ON_COPY,
527528
&derive::UNSAFE_DERIVE_DESERIALIZE,
529+
&disallowed_method::DISALLOWED_METHOD,
528530
&doc::DOC_MARKDOWN,
529531
&doc::MISSING_ERRORS_DOC,
530532
&doc::MISSING_SAFETY_DOC,
@@ -1118,6 +1120,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11181120
store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
11191121
store.register_late_pass(|| box manual_strip::ManualStrip);
11201122
store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
1123+
let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
1124+
store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(disallowed_methods.clone()));
1125+
11211126

11221127
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
11231128
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1807,6 +1812,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
18071812
store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
18081813
LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
18091814
LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY),
1815+
LintId::of(&disallowed_method::DISALLOWED_METHOD),
18101816
LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM),
18111817
LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS),
18121818
LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS),

clippy_lints/src/utils/conf.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ define_Conf! {
164164
(max_fn_params_bools, "max_fn_params_bools": u64, 3),
165165
/// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests).
166166
(warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false),
167+
/// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses
168+
(disallowed_methods, "disallowed_methods": Vec<String>, ["disallowed_method::Foo::bad_method", "disallowed_method::Baz::bad_method", "disallowed_method::Quux::bad_method"].iter().map(ToString::to_string).collect()),
167169
}
168170

169171
impl Default for Conf {

src/lintlist/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
381381
deprecation: None,
382382
module: "derive",
383383
},
384+
Lint {
385+
name: "disallowed_method",
386+
group: "nursery",
387+
desc: "default lint description",
388+
deprecation: None,
389+
module: "disallowed_method",
390+
},
384391
Lint {
385392
name: "diverging_sub_expression",
386393
group: "complexity",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match"]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![warn(clippy::disallowed_method)]
2+
3+
extern crate regex;
4+
use regex::Regex;
5+
6+
fn main() {
7+
let a = vec![1, 2, 3, 4];
8+
let re = Regex::new(r"ab.*c").unwrap();
9+
10+
re.is_match("abc");
11+
12+
a.iter().sum::<i32>();
13+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: Use of a disallowed method `regex::re_unicode::Regex::is_match`
2+
--> $DIR/conf_disallowed_method.rs:10:5
3+
|
4+
LL | re.is_match("abc");
5+
| ^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::disallowed-method` implied by `-D warnings`
8+
9+
error: Use of a disallowed method `core::iter::traits::iterator::Iterator::sum`
10+
--> $DIR/conf_disallowed_method.rs:12:5
11+
|
12+
LL | a.iter().sum::<i32>();
13+
| ^^^^^^^^^^^^^^^^^^^^^
14+
15+
error: aborting due to 2 previous errors
16+

tests/ui/disallowed_method.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#![warn(clippy::disallowed_method)]
2+
#![allow(clippy::no_effect, clippy::many_single_char_names)]
3+
4+
struct ImplStruct;
5+
6+
trait Baz {
7+
fn bad_method(self);
8+
}
9+
10+
impl Baz for ImplStruct {
11+
fn bad_method(self) {}
12+
}
13+
14+
struct Foo;
15+
16+
impl Foo {
17+
fn bad_method(self) {}
18+
}
19+
20+
struct StaticStruct;
21+
22+
trait Quux {
23+
fn bad_method();
24+
}
25+
26+
impl Quux for StaticStruct {
27+
fn bad_method() {}
28+
}
29+
30+
struct NormalStruct;
31+
32+
impl NormalStruct {
33+
fn bad_method(self) {}
34+
}
35+
36+
struct AttrStruct {
37+
bad_method: i32,
38+
}
39+
40+
fn main() {
41+
let b = ImplStruct;
42+
let f = Foo;
43+
let c = ImplStruct;
44+
let n = NormalStruct;
45+
let a = AttrStruct{ bad_method: 5 };
46+
47+
// lint these
48+
b.bad_method();
49+
c.bad_method();
50+
f.bad_method();
51+
// these are good
52+
// good because not a method call (ExprKind => Call)
53+
StaticStruct::bad_method();
54+
n.bad_method();
55+
a.bad_method;
56+
}

tests/ui/disallowed_method.stderr

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: Use of a disallowed method `disallowed_method::Baz::bad_method`
2+
--> $DIR/disallowed_method.rs:48:5
3+
|
4+
LL | b.bad_method();
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::disallowed-method` implied by `-D warnings`
8+
9+
error: Use of a disallowed method `disallowed_method::Baz::bad_method`
10+
--> $DIR/disallowed_method.rs:49:5
11+
|
12+
LL | c.bad_method();
13+
| ^^^^^^^^^^^^^^
14+
15+
error: Use of a disallowed method `disallowed_method::Foo::bad_method`
16+
--> $DIR/disallowed_method.rs:50:5
17+
|
18+
LL | f.bad_method();
19+
| ^^^^^^^^^^^^^^
20+
21+
error: aborting due to 3 previous errors
22+

0 commit comments

Comments
 (0)