]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/functions/mod.rs
Auto merge of #7004 - Jarcho:manual_map_if_then_else, r=camsteffen
[rust.git] / clippy_lints / src / functions / mod.rs
1 mod must_use;
2 mod not_unsafe_ptr_arg_deref;
3 mod result_unit_err;
4 mod too_many_arguments;
5 mod too_many_lines;
6
7 use rustc_hir as hir;
8 use rustc_hir::intravisit;
9 use rustc_lint::{LateContext, LateLintPass};
10 use rustc_session::{declare_tool_lint, impl_lint_pass};
11 use rustc_span::Span;
12
13 declare_clippy_lint! {
14     /// **What it does:** Checks for functions with too many parameters.
15     ///
16     /// **Why is this bad?** Functions with lots of parameters are considered bad
17     /// style and reduce readability (“what does the 5th parameter mean?”). Consider
18     /// grouping some parameters into a new type.
19     ///
20     /// **Known problems:** None.
21     ///
22     /// **Example:**
23     /// ```rust
24     /// # struct Color;
25     /// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
26     ///     // ..
27     /// }
28     /// ```
29     pub TOO_MANY_ARGUMENTS,
30     complexity,
31     "functions with too many arguments"
32 }
33
34 declare_clippy_lint! {
35     /// **What it does:** Checks for functions with a large amount of lines.
36     ///
37     /// **Why is this bad?** Functions with a lot of lines are harder to understand
38     /// due to having to look at a larger amount of code to understand what the
39     /// function is doing. Consider splitting the body of the function into
40     /// multiple functions.
41     ///
42     /// **Known problems:** None.
43     ///
44     /// **Example:**
45     /// ```rust
46     /// fn im_too_long() {
47     ///     println!("");
48     ///     // ... 100 more LoC
49     ///     println!("");
50     /// }
51     /// ```
52     pub TOO_MANY_LINES,
53     pedantic,
54     "functions with too many lines"
55 }
56
57 declare_clippy_lint! {
58     /// **What it does:** Checks for public functions that dereference raw pointer
59     /// arguments but are not marked `unsafe`.
60     ///
61     /// **Why is this bad?** The function should probably be marked `unsafe`, since
62     /// for an arbitrary raw pointer, there is no way of telling for sure if it is
63     /// valid.
64     ///
65     /// **Known problems:**
66     ///
67     /// * It does not check functions recursively so if the pointer is passed to a
68     /// private non-`unsafe` function which does the dereferencing, the lint won't
69     /// trigger.
70     /// * It only checks for arguments whose type are raw pointers, not raw pointers
71     /// got from an argument in some other way (`fn foo(bar: &[*const u8])` or
72     /// `some_argument.get_raw_ptr()`).
73     ///
74     /// **Example:**
75     /// ```rust,ignore
76     /// // Bad
77     /// pub fn foo(x: *const u8) {
78     ///     println!("{}", unsafe { *x });
79     /// }
80     ///
81     /// // Good
82     /// pub unsafe fn foo(x: *const u8) {
83     ///     println!("{}", unsafe { *x });
84     /// }
85     /// ```
86     pub NOT_UNSAFE_PTR_ARG_DEREF,
87     correctness,
88     "public functions dereferencing raw pointer arguments but not marked `unsafe`"
89 }
90
91 declare_clippy_lint! {
92     /// **What it does:** Checks for a [`#[must_use]`] attribute on
93     /// unit-returning functions and methods.
94     ///
95     /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
96     ///
97     /// **Why is this bad?** Unit values are useless. The attribute is likely
98     /// a remnant of a refactoring that removed the return type.
99     ///
100     /// **Known problems:** None.
101     ///
102     /// **Examples:**
103     /// ```rust
104     /// #[must_use]
105     /// fn useless() { }
106     /// ```
107     pub MUST_USE_UNIT,
108     style,
109     "`#[must_use]` attribute on a unit-returning function / method"
110 }
111
112 declare_clippy_lint! {
113     /// **What it does:** Checks for a [`#[must_use]`] attribute without
114     /// further information on functions and methods that return a type already
115     /// marked as `#[must_use]`.
116     ///
117     /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
118     ///
119     /// **Why is this bad?** The attribute isn't needed. Not using the result
120     /// will already be reported. Alternatively, one can add some text to the
121     /// attribute to improve the lint message.
122     ///
123     /// **Known problems:** None.
124     ///
125     /// **Examples:**
126     /// ```rust
127     /// #[must_use]
128     /// fn double_must_use() -> Result<(), ()> {
129     ///     unimplemented!();
130     /// }
131     /// ```
132     pub DOUBLE_MUST_USE,
133     style,
134     "`#[must_use]` attribute on a `#[must_use]`-returning function / method"
135 }
136
137 declare_clippy_lint! {
138     /// **What it does:** Checks for public functions that have no
139     /// [`#[must_use]`] attribute, but return something not already marked
140     /// must-use, have no mutable arg and mutate no statics.
141     ///
142     /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
143     ///
144     /// **Why is this bad?** Not bad at all, this lint just shows places where
145     /// you could add the attribute.
146     ///
147     /// **Known problems:** The lint only checks the arguments for mutable
148     /// types without looking if they are actually changed. On the other hand,
149     /// it also ignores a broad range of potentially interesting side effects,
150     /// because we cannot decide whether the programmer intends the function to
151     /// be called for the side effect or the result. Expect many false
152     /// positives. At least we don't lint if the result type is unit or already
153     /// `#[must_use]`.
154     ///
155     /// **Examples:**
156     /// ```rust
157     /// // this could be annotated with `#[must_use]`.
158     /// fn id<T>(t: T) -> T { t }
159     /// ```
160     pub MUST_USE_CANDIDATE,
161     pedantic,
162     "function or method that could take a `#[must_use]` attribute"
163 }
164
165 declare_clippy_lint! {
166     /// **What it does:** Checks for public functions that return a `Result`
167     /// with an `Err` type of `()`. It suggests using a custom type that
168     /// implements `std::error::Error`.
169     ///
170     /// **Why is this bad?** Unit does not implement `Error` and carries no
171     /// further information about what went wrong.
172     ///
173     /// **Known problems:** Of course, this lint assumes that `Result` is used
174     /// for a fallible operation (which is after all the intended use). However
175     /// code may opt to (mis)use it as a basic two-variant-enum. In that case,
176     /// the suggestion is misguided, and the code should use a custom enum
177     /// instead.
178     ///
179     /// **Examples:**
180     /// ```rust
181     /// pub fn read_u8() -> Result<u8, ()> { Err(()) }
182     /// ```
183     /// should become
184     /// ```rust,should_panic
185     /// use std::fmt;
186     ///
187     /// #[derive(Debug)]
188     /// pub struct EndOfStream;
189     ///
190     /// impl fmt::Display for EndOfStream {
191     ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192     ///         write!(f, "End of Stream")
193     ///     }
194     /// }
195     ///
196     /// impl std::error::Error for EndOfStream { }
197     ///
198     /// pub fn read_u8() -> Result<u8, EndOfStream> { Err(EndOfStream) }
199     ///# fn main() {
200     ///#     read_u8().unwrap();
201     ///# }
202     /// ```
203     ///
204     /// Note that there are crates that simplify creating the error type, e.g.
205     /// [`thiserror`](https://docs.rs/thiserror).
206     pub RESULT_UNIT_ERR,
207     style,
208     "public function returning `Result` with an `Err` type of `()`"
209 }
210
211 #[derive(Copy, Clone)]
212 pub struct Functions {
213     too_many_arguments_threshold: u64,
214     too_many_lines_threshold: u64,
215 }
216
217 impl Functions {
218     pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64) -> Self {
219         Self {
220             too_many_arguments_threshold,
221             too_many_lines_threshold,
222         }
223     }
224 }
225
226 impl_lint_pass!(Functions => [
227     TOO_MANY_ARGUMENTS,
228     TOO_MANY_LINES,
229     NOT_UNSAFE_PTR_ARG_DEREF,
230     MUST_USE_UNIT,
231     DOUBLE_MUST_USE,
232     MUST_USE_CANDIDATE,
233     RESULT_UNIT_ERR,
234 ]);
235
236 impl<'tcx> LateLintPass<'tcx> for Functions {
237     fn check_fn(
238         &mut self,
239         cx: &LateContext<'tcx>,
240         kind: intravisit::FnKind<'tcx>,
241         decl: &'tcx hir::FnDecl<'_>,
242         body: &'tcx hir::Body<'_>,
243         span: Span,
244         hir_id: hir::HirId,
245     ) {
246         too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold);
247         too_many_lines::check_fn(cx, span, body, self.too_many_lines_threshold);
248         not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, hir_id);
249     }
250
251     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
252         must_use::check_item(cx, item);
253         result_unit_err::check_item(cx, item);
254     }
255
256     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
257         must_use::check_impl_item(cx, item);
258         result_unit_err::check_impl_item(cx, item);
259     }
260
261     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
262         too_many_arguments::check_trait_item(cx, item, self.too_many_arguments_threshold);
263         not_unsafe_ptr_arg_deref::check_trait_item(cx, item);
264         must_use::check_trait_item(cx, item);
265         result_unit_err::check_trait_item(cx, item);
266     }
267 }