add disallowed_method lint

This commit is contained in:
Frank 2020-09-24 15:32:03 -05:00
parent cc1998f7b3
commit 1479c18396
10 changed files with 199 additions and 0 deletions

View file

@ -1559,6 +1559,7 @@ Released 2018-09-13
[`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof
[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons

View file

@ -0,0 +1,75 @@
use crate::utils::span_lint;
use rustc_data_structures::fx::FxHashSet;
use rustc_lint::{LateLintPass, LateContext};
use rustc_session::{impl_lint_pass, declare_tool_lint};
use rustc_hir::*;
use rustc_span::Symbol;
declare_clippy_lint! {
/// **What it does:** Lints for specific trait methods defined in clippy.toml
///
/// **Why is this bad?** Some methods are undesirable in certain contexts,
/// and it would be beneficial to lint for them as needed.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// // example code where clippy issues a warning
/// foo.bad_method(); // Foo is disallowed
/// ```
/// Use instead:
/// ```rust
/// // example code which does not raise clippy warning
/// GoodStruct.bad_method(); // not disallowed
/// ```
pub DISALLOWED_METHOD,
nursery,
"used disallowed method call"
}
#[derive(Clone, Debug)]
pub struct DisallowedMethod {
disallowed: FxHashSet<Vec<Symbol>>,
}
impl DisallowedMethod {
pub fn new(disallowed: FxHashSet<String>) -> Self {
Self {
disallowed: disallowed.iter()
.map(|s| {
s.split("::").map(|seg| Symbol::intern(seg)).collect::<Vec<_>>()
})
.collect(),
}
}
}
impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]);
impl <'tcx> LateLintPass<'tcx> for DisallowedMethod {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::MethodCall(path, _, _args, _) = &expr.kind {
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
let method_call = cx.get_def_path(def_id);
if self.disallowed.contains(&method_call) {
span_lint(
cx,
DISALLOWED_METHOD,
expr.span,
&format!(
"Use of a disallowed method `{}`",
method_call
.iter()
.map(|s| s.to_ident_string())
.collect::<Vec<_>>()
.join("::"),
)
);
}
}
}
}

View file

@ -175,6 +175,7 @@ mod dbg_macro;
mod default_trait_access;
mod dereference;
mod derive;
mod disallowed_method;
mod doc;
mod double_comparison;
mod double_parens;
@ -525,6 +526,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&derive::DERIVE_ORD_XOR_PARTIAL_ORD,
&derive::EXPL_IMPL_CLONE_ON_COPY,
&derive::UNSAFE_DERIVE_DESERIALIZE,
&disallowed_method::DISALLOWED_METHOD,
&doc::DOC_MARKDOWN,
&doc::MISSING_ERRORS_DOC,
&doc::MISSING_SAFETY_DOC,
@ -1118,6 +1120,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
store.register_late_pass(|| box manual_strip::ManualStrip);
store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(disallowed_methods.clone()));
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@ -1807,6 +1812,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY),
LintId::of(&disallowed_method::DISALLOWED_METHOD),
LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM),
LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS),
LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS),

View file

@ -164,6 +164,8 @@ define_Conf! {
(max_fn_params_bools, "max_fn_params_bools": u64, 3),
/// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests).
(warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false),
/// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses
(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()),
}
impl Default for Conf {

View file

@ -381,6 +381,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
deprecation: None,
module: "derive",
},
Lint {
name: "disallowed_method",
group: "nursery",
desc: "default lint description",
deprecation: None,
module: "disallowed_method",
},
Lint {
name: "diverging_sub_expression",
group: "complexity",

View file

@ -0,0 +1 @@
disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match"]

View file

@ -0,0 +1,13 @@
#![warn(clippy::disallowed_method)]
extern crate regex;
use regex::Regex;
fn main() {
let a = vec![1, 2, 3, 4];
let re = Regex::new(r"ab.*c").unwrap();
re.is_match("abc");
a.iter().sum::<i32>();
}

View file

@ -0,0 +1,16 @@
error: Use of a disallowed method `regex::re_unicode::Regex::is_match`
--> $DIR/conf_disallowed_method.rs:10:5
|
LL | re.is_match("abc");
| ^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::disallowed-method` implied by `-D warnings`
error: Use of a disallowed method `core::iter::traits::iterator::Iterator::sum`
--> $DIR/conf_disallowed_method.rs:12:5
|
LL | a.iter().sum::<i32>();
| ^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View file

@ -0,0 +1,56 @@
#![warn(clippy::disallowed_method)]
#![allow(clippy::no_effect, clippy::many_single_char_names)]
struct ImplStruct;
trait Baz {
fn bad_method(self);
}
impl Baz for ImplStruct {
fn bad_method(self) {}
}
struct Foo;
impl Foo {
fn bad_method(self) {}
}
struct StaticStruct;
trait Quux {
fn bad_method();
}
impl Quux for StaticStruct {
fn bad_method() {}
}
struct NormalStruct;
impl NormalStruct {
fn bad_method(self) {}
}
struct AttrStruct {
bad_method: i32,
}
fn main() {
let b = ImplStruct;
let f = Foo;
let c = ImplStruct;
let n = NormalStruct;
let a = AttrStruct{ bad_method: 5 };
// lint these
b.bad_method();
c.bad_method();
f.bad_method();
// these are good
// good because not a method call (ExprKind => Call)
StaticStruct::bad_method();
n.bad_method();
a.bad_method;
}

View file

@ -0,0 +1,22 @@
error: Use of a disallowed method `disallowed_method::Baz::bad_method`
--> $DIR/disallowed_method.rs:48:5
|
LL | b.bad_method();
| ^^^^^^^^^^^^^^
|
= note: `-D clippy::disallowed-method` implied by `-D warnings`
error: Use of a disallowed method `disallowed_method::Baz::bad_method`
--> $DIR/disallowed_method.rs:49:5
|
LL | c.bad_method();
| ^^^^^^^^^^^^^^
error: Use of a disallowed method `disallowed_method::Foo::bad_method`
--> $DIR/disallowed_method.rs:50:5
|
LL | f.bad_method();
| ^^^^^^^^^^^^^^
error: aborting due to 3 previous errors