about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFrank <lifrank@grinnell.edu>2020-09-24 15:32:03 -0500
committerFrank <lifrank@grinnell.edu>2020-09-25 11:09:04 -0500
commit1479c18396d764482aa0e56b372c5f57a97c102b (patch)
tree5d24b1f867251f71ef3f90a04a25a2a047719845
parentcc1998f7b3cc04c891f92c62a52c0c45fa4c145a (diff)
downloadrust-1479c18396d764482aa0e56b372c5f57a97c102b.tar.gz
rust-1479c18396d764482aa0e56b372c5f57a97c102b.zip
add disallowed_method lint
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/disallowed_method.rs75
-rw-r--r--clippy_lints/src/lib.rs6
-rw-r--r--clippy_lints/src/utils/conf.rs2
-rw-r--r--src/lintlist/mod.rs7
-rw-r--r--tests/ui-toml/toml_disallowed_method/clippy.toml1
-rw-r--r--tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs13
-rw-r--r--tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr16
-rw-r--r--tests/ui/disallowed_method.rs56
-rw-r--r--tests/ui/disallowed_method.stderr22
10 files changed, 199 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d1dfe36ffd8..575cbd60792 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/clippy_lints/src/disallowed_method.rs b/clippy_lints/src/disallowed_method.rs
new file mode 100644
index 00000000000..7088b2718f2
--- /dev/null
+++ b/clippy_lints/src/disallowed_method.rs
@@ -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("::"),
+                    )
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 58112ac8da5..7c886ab87d0 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -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),
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 9c5a12ea9c8..07591ce2229 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -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 {
diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs
index 9603023ed06..a77bbcb0abe 100644
--- a/src/lintlist/mod.rs
+++ b/src/lintlist/mod.rs
@@ -382,6 +382,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "derive",
     },
     Lint {
+        name: "disallowed_method",
+        group: "nursery",
+        desc: "default lint description",
+        deprecation: None,
+        module: "disallowed_method",
+    },
+    Lint {
         name: "diverging_sub_expression",
         group: "complexity",
         desc: "whether an expression contains a diverging sub expression",
diff --git a/tests/ui-toml/toml_disallowed_method/clippy.toml b/tests/ui-toml/toml_disallowed_method/clippy.toml
new file mode 100644
index 00000000000..a1f515e443d
--- /dev/null
+++ b/tests/ui-toml/toml_disallowed_method/clippy.toml
@@ -0,0 +1 @@
+disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match"]
diff --git a/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs
new file mode 100644
index 00000000000..3d3f0729abd
--- /dev/null
+++ b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs
@@ -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>();
+}
diff --git a/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr
new file mode 100644
index 00000000000..5da551cb430
--- /dev/null
+++ b/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr
@@ -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
+
diff --git a/tests/ui/disallowed_method.rs b/tests/ui/disallowed_method.rs
new file mode 100644
index 00000000000..a54a04b4d2c
--- /dev/null
+++ b/tests/ui/disallowed_method.rs
@@ -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;
+}
diff --git a/tests/ui/disallowed_method.stderr b/tests/ui/disallowed_method.stderr
new file mode 100644
index 00000000000..93dabf38cfc
--- /dev/null
+++ b/tests/ui/disallowed_method.stderr
@@ -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
+