Skip to content

Commit 83b7b16

Browse files
committed
Auto merge of #6674 - phlip9:disallowed_functions, r=llogiq
disallowed_methods: Support functions in addition to methods ## Context: Hey all! I have a particular use case where I'd like to ban certain functions in a code base I work on. For example, I want to ban `Instant::now()` (among others) as we have a time service for mocking time in deterministic simulation tests. Obviously, it doesn't make sense to include a lint like this for all clippy users. Imagine my excitement when I spotted the new `disallowed_methods` lint in clippy--perfect! Unfortunately, after playing around with it for a bit, I was frustrated to realize that it didn't support functions like `Instant::now()`, so I've added support for them in this PR. It might also make sense to rename the lint from `disallowed_methods` -> `disallowed_functions`, though I've held off from including that rename in this change, since I'm unsure of clippy's breaking change policy. ## Change Support functions in addition to methods. In other words, support: `disallowed_methods = ["alloc::vec::Vec::new"]` (a function) in addition to `disallowed_methods = ["alloc::vec::Vec::leak"]` (a method). Improve the documentation to clarify that users must specify the full qualified path for each disallowed function, which can be confusing for reexports. Include an example `clippy.toml`. Simplify the actual lint pass so we can reuse `utils::fn_def_id`. changelog: disallowed_method: Now supports functions in addition to methods
2 parents ad9ceee + 7b7e3ca commit 83b7b16

File tree

5 files changed

+48
-27
lines changed

5 files changed

+48
-27
lines changed

clippy_lints/src/disallowed_method.rs

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,47 @@
1-
use crate::utils::span_lint;
1+
use crate::utils::{fn_def_id, span_lint};
22

33
use rustc_data_structures::fx::FxHashSet;
4-
use rustc_hir::{Expr, ExprKind};
4+
use rustc_hir::Expr;
55
use rustc_lint::{LateContext, LateLintPass};
66
use rustc_session::{declare_tool_lint, impl_lint_pass};
77
use rustc_span::Symbol;
88

99
declare_clippy_lint! {
10-
/// **What it does:** Lints for specific trait methods defined in clippy.toml
10+
/// **What it does:** Denies the configured methods and functions in clippy.toml
1111
///
1212
/// **Why is this bad?** Some methods are undesirable in certain contexts,
13-
/// and it would be beneficial to lint for them as needed.
13+
/// and it's beneficial to lint for them as needed.
1414
///
15-
/// **Known problems:** None.
15+
/// **Known problems:** Currently, you must write each function as a
16+
/// fully-qualified path. This lint doesn't support aliases or reexported
17+
/// names; be aware that many types in `std` are actually reexports.
18+
///
19+
/// For example, if you want to disallow `Duration::as_secs`, your clippy.toml
20+
/// configuration would look like
21+
/// `disallowed-methods = ["core::time::Duration::as_secs"]` and not
22+
/// `disallowed-methods = ["std::time::Duration::as_secs"]` as you might expect.
1623
///
1724
/// **Example:**
1825
///
26+
/// An example clippy.toml configuration:
27+
/// ```toml
28+
/// # clippy.toml
29+
/// disallowed-methods = ["alloc::vec::Vec::leak", "std::time::Instant::now"]
30+
/// ```
31+
///
1932
/// ```rust,ignore
20-
/// // example code where clippy issues a warning
21-
/// foo.bad_method(); // Foo::bad_method is disallowed in the configuration
33+
/// // Example code where clippy issues a warning
34+
/// let xs = vec![1, 2, 3, 4];
35+
/// xs.leak(); // Vec::leak is disallowed in the config.
36+
///
37+
/// let _now = Instant::now(); // Instant::now is disallowed in the config.
2238
/// ```
39+
///
2340
/// Use instead:
2441
/// ```rust,ignore
25-
/// // example code which does not raise clippy warning
26-
/// goodStruct.bad_method(); // GoodStruct::bad_method is not disallowed
42+
/// // Example code which does not raise clippy warning
43+
/// let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config.
44+
/// xs.push(123); // Vec::push is _not_ disallowed in the config.
2745
/// ```
2846
pub DISALLOWED_METHOD,
2947
nursery,
@@ -50,22 +68,20 @@ impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]);
5068

5169
impl<'tcx> LateLintPass<'tcx> for DisallowedMethod {
5270
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
53-
if let ExprKind::MethodCall(_path, _, _args, _) = &expr.kind {
54-
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
55-
56-
let method_call = cx.get_def_path(def_id);
57-
if self.disallowed.contains(&method_call) {
58-
let method = method_call
59-
.iter()
60-
.map(|s| s.to_ident_string())
71+
if let Some(def_id) = fn_def_id(cx, expr) {
72+
let func_path = cx.get_def_path(def_id);
73+
if self.disallowed.contains(&func_path) {
74+
let func_path_string = func_path
75+
.into_iter()
76+
.map(Symbol::to_ident_string)
6177
.collect::<Vec<_>>()
6278
.join("::");
6379

6480
span_lint(
6581
cx,
6682
DISALLOWED_METHOD,
6783
expr.span,
68-
&format!("use of a disallowed method `{}`", method),
84+
&format!("use of a disallowed method `{}`", func_path_string),
6985
);
7086
}
7187
}

clippy_lints/src/utils/conf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ define_Conf! {
169169
(max_fn_params_bools, "max_fn_params_bools": u64, 3),
170170
/// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests).
171171
(warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false),
172-
/// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses
172+
/// Lint: DISALLOWED_METHOD. The list of disallowed methods, written as fully qualified paths.
173173
(disallowed_methods, "disallowed_methods": Vec<String>, Vec::<String>::new()),
174174
/// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators.
175175
(unreadable_literal_lint_fractions, "unreadable_literal_lint_fractions": bool, true),
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match"]
1+
disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match", "regex::re_unicode::Regex::new"]

tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ extern crate regex;
44
use regex::Regex;
55

66
fn main() {
7-
let a = vec![1, 2, 3, 4];
87
let re = Regex::new(r"ab.*c").unwrap();
9-
108
re.is_match("abc");
119

10+
let a = vec![1, 2, 3, 4];
1211
a.iter().sum::<i32>();
1312
}
Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
1+
error: use of a disallowed method `regex::re_unicode::Regex::new`
2+
--> $DIR/conf_disallowed_method.rs:7:14
3+
|
4+
LL | let re = Regex::new(r"ab.*c").unwrap();
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::disallowed-method` implied by `-D warnings`
8+
19
error: use of a disallowed method `regex::re_unicode::Regex::is_match`
2-
--> $DIR/conf_disallowed_method.rs:10:5
10+
--> $DIR/conf_disallowed_method.rs:8:5
311
|
412
LL | re.is_match("abc");
513
| ^^^^^^^^^^^^^^^^^^
6-
|
7-
= note: `-D clippy::disallowed-method` implied by `-D warnings`
814

915
error: use of a disallowed method `core::iter::traits::iterator::Iterator::sum`
10-
--> $DIR/conf_disallowed_method.rs:12:5
16+
--> $DIR/conf_disallowed_method.rs:11:5
1117
|
1218
LL | a.iter().sum::<i32>();
1319
| ^^^^^^^^^^^^^^^^^^^^^
1420

15-
error: aborting due to 2 previous errors
21+
error: aborting due to 3 previous errors
1622

0 commit comments

Comments
 (0)