]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/functions/mod.rs
Auto merge of #105121 - oli-obk:simpler-cheaper-dump_mir, r=nnethercote
[rust.git] / src / tools / clippy / clippy_lints / src / functions / mod.rs
1 mod misnamed_getters;
2 mod must_use;
3 mod not_unsafe_ptr_arg_deref;
4 mod result;
5 mod too_many_arguments;
6 mod too_many_lines;
7
8 use rustc_hir as hir;
9 use rustc_hir::intravisit;
10 use rustc_lint::{LateContext, LateLintPass};
11 use rustc_session::{declare_tool_lint, impl_lint_pass};
12 use rustc_span::Span;
13
14 declare_clippy_lint! {
15     /// ### What it does
16     /// Checks for functions with too many parameters.
17     ///
18     /// ### Why is this bad?
19     /// Functions with lots of parameters are considered bad
20     /// style and reduce readability (“what does the 5th parameter mean?”). Consider
21     /// grouping some parameters into a new type.
22     ///
23     /// ### Example
24     /// ```rust
25     /// # struct Color;
26     /// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
27     ///     // ..
28     /// }
29     /// ```
30     #[clippy::version = "pre 1.29.0"]
31     pub TOO_MANY_ARGUMENTS,
32     complexity,
33     "functions with too many arguments"
34 }
35
36 declare_clippy_lint! {
37     /// ### What it does
38     /// Checks for functions with a large amount of lines.
39     ///
40     /// ### Why is this bad?
41     /// Functions with a lot of lines are harder to understand
42     /// due to having to look at a larger amount of code to understand what the
43     /// function is doing. Consider splitting the body of the function into
44     /// multiple functions.
45     ///
46     /// ### Example
47     /// ```rust
48     /// fn im_too_long() {
49     ///     println!("");
50     ///     // ... 100 more LoC
51     ///     println!("");
52     /// }
53     /// ```
54     #[clippy::version = "1.34.0"]
55     pub TOO_MANY_LINES,
56     pedantic,
57     "functions with too many lines"
58 }
59
60 declare_clippy_lint! {
61     /// ### What it does
62     /// Checks for public functions that dereference raw pointer
63     /// arguments but are not marked `unsafe`.
64     ///
65     /// ### Why is this bad?
66     /// The function should probably be marked `unsafe`, since
67     /// for an arbitrary raw pointer, there is no way of telling for sure if it is
68     /// valid.
69     ///
70     /// ### Known problems
71     /// * It does not check functions recursively so if the pointer is passed to a
72     /// private non-`unsafe` function which does the dereferencing, the lint won't
73     /// trigger.
74     /// * It only checks for arguments whose type are raw pointers, not raw pointers
75     /// got from an argument in some other way (`fn foo(bar: &[*const u8])` or
76     /// `some_argument.get_raw_ptr()`).
77     ///
78     /// ### Example
79     /// ```rust,ignore
80     /// pub fn foo(x: *const u8) {
81     ///     println!("{}", unsafe { *x });
82     /// }
83     /// ```
84     ///
85     /// Use instead:
86     /// ```rust,ignore
87     /// pub unsafe fn foo(x: *const u8) {
88     ///     println!("{}", unsafe { *x });
89     /// }
90     /// ```
91     #[clippy::version = "pre 1.29.0"]
92     pub NOT_UNSAFE_PTR_ARG_DEREF,
93     correctness,
94     "public functions dereferencing raw pointer arguments but not marked `unsafe`"
95 }
96
97 declare_clippy_lint! {
98     /// ### What it does
99     /// Checks for a `#[must_use]` attribute on
100     /// unit-returning functions and methods.
101     ///
102     /// ### Why is this bad?
103     /// Unit values are useless. The attribute is likely
104     /// a remnant of a refactoring that removed the return type.
105     ///
106     /// ### Examples
107     /// ```rust
108     /// #[must_use]
109     /// fn useless() { }
110     /// ```
111     #[clippy::version = "1.40.0"]
112     pub MUST_USE_UNIT,
113     style,
114     "`#[must_use]` attribute on a unit-returning function / method"
115 }
116
117 declare_clippy_lint! {
118     /// ### What it does
119     /// Checks for a `#[must_use]` attribute without
120     /// further information on functions and methods that return a type already
121     /// marked as `#[must_use]`.
122     ///
123     /// ### Why is this bad?
124     /// The attribute isn't needed. Not using the result
125     /// will already be reported. Alternatively, one can add some text to the
126     /// attribute to improve the lint message.
127     ///
128     /// ### Examples
129     /// ```rust
130     /// #[must_use]
131     /// fn double_must_use() -> Result<(), ()> {
132     ///     unimplemented!();
133     /// }
134     /// ```
135     #[clippy::version = "1.40.0"]
136     pub DOUBLE_MUST_USE,
137     style,
138     "`#[must_use]` attribute on a `#[must_use]`-returning function / method"
139 }
140
141 declare_clippy_lint! {
142     /// ### What it does
143     /// Checks for public functions that have no
144     /// `#[must_use]` attribute, but return something not already marked
145     /// must-use, have no mutable arg and mutate no statics.
146     ///
147     /// ### Why is this bad?
148     /// Not bad at all, this lint just shows places where
149     /// you could add the attribute.
150     ///
151     /// ### Known problems
152     /// The lint only checks the arguments for mutable
153     /// types without looking if they are actually changed. On the other hand,
154     /// it also ignores a broad range of potentially interesting side effects,
155     /// because we cannot decide whether the programmer intends the function to
156     /// be called for the side effect or the result. Expect many false
157     /// positives. At least we don't lint if the result type is unit or already
158     /// `#[must_use]`.
159     ///
160     /// ### Examples
161     /// ```rust
162     /// // this could be annotated with `#[must_use]`.
163     /// fn id<T>(t: T) -> T { t }
164     /// ```
165     #[clippy::version = "1.40.0"]
166     pub MUST_USE_CANDIDATE,
167     pedantic,
168     "function or method that could take a `#[must_use]` attribute"
169 }
170
171 declare_clippy_lint! {
172     /// ### What it does
173     /// Checks for public functions that return a `Result`
174     /// with an `Err` type of `()`. It suggests using a custom type that
175     /// implements `std::error::Error`.
176     ///
177     /// ### Why is this bad?
178     /// Unit does not implement `Error` and carries no
179     /// further information about what went wrong.
180     ///
181     /// ### Known problems
182     /// Of course, this lint assumes that `Result` is used
183     /// for a fallible operation (which is after all the intended use). However
184     /// code may opt to (mis)use it as a basic two-variant-enum. In that case,
185     /// the suggestion is misguided, and the code should use a custom enum
186     /// instead.
187     ///
188     /// ### Examples
189     /// ```rust
190     /// pub fn read_u8() -> Result<u8, ()> { Err(()) }
191     /// ```
192     /// should become
193     /// ```rust,should_panic
194     /// use std::fmt;
195     ///
196     /// #[derive(Debug)]
197     /// pub struct EndOfStream;
198     ///
199     /// impl fmt::Display for EndOfStream {
200     ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201     ///         write!(f, "End of Stream")
202     ///     }
203     /// }
204     ///
205     /// impl std::error::Error for EndOfStream { }
206     ///
207     /// pub fn read_u8() -> Result<u8, EndOfStream> { Err(EndOfStream) }
208     ///# fn main() {
209     ///#     read_u8().unwrap();
210     ///# }
211     /// ```
212     ///
213     /// Note that there are crates that simplify creating the error type, e.g.
214     /// [`thiserror`](https://docs.rs/thiserror).
215     #[clippy::version = "1.49.0"]
216     pub RESULT_UNIT_ERR,
217     style,
218     "public function returning `Result` with an `Err` type of `()`"
219 }
220
221 declare_clippy_lint! {
222     /// ### What it does
223     /// Checks for functions that return `Result` with an unusually large
224     /// `Err`-variant.
225     ///
226     /// ### Why is this bad?
227     /// A `Result` is at least as large as the `Err`-variant. While we
228     /// expect that variant to be seldomly used, the compiler needs to reserve
229     /// and move that much memory every single time.
230     ///
231     /// ### Known problems
232     /// The size determined by Clippy is platform-dependent.
233     ///
234     /// ### Examples
235     /// ```rust
236     /// pub enum ParseError {
237     ///     UnparsedBytes([u8; 512]),
238     ///     UnexpectedEof,
239     /// }
240     ///
241     /// // The `Result` has at least 512 bytes, even in the `Ok`-case
242     /// pub fn parse() -> Result<(), ParseError> {
243     ///     Ok(())
244     /// }
245     /// ```
246     /// should be
247     /// ```
248     /// pub enum ParseError {
249     ///     UnparsedBytes(Box<[u8; 512]>),
250     ///     UnexpectedEof,
251     /// }
252     ///
253     /// // The `Result` is slightly larger than a pointer
254     /// pub fn parse() -> Result<(), ParseError> {
255     ///     Ok(())
256     /// }
257     /// ```
258     #[clippy::version = "1.65.0"]
259     pub RESULT_LARGE_ERR,
260     perf,
261     "function returning `Result` with large `Err` type"
262 }
263
264 declare_clippy_lint! {
265     /// ### What it does
266     /// Checks for getter methods that return a field that doesn't correspond
267     /// to the name of the method, when there is a field's whose name matches that of the method.
268     ///
269     /// ### Why is this bad?
270     /// It is most likely that such a  method is a bug caused by a typo or by copy-pasting.
271     ///
272     /// ### Example
273
274     /// ```rust
275     /// struct A {
276     ///     a: String,
277     ///     b: String,
278     /// }
279     ///
280     /// impl A {
281     ///     fn a(&self) -> &str{
282     ///         &self.b
283     ///     }
284     /// }
285
286     /// ```
287     /// Use instead:
288     /// ```rust
289     /// struct A {
290     ///     a: String,
291     ///     b: String,
292     /// }
293     ///
294     /// impl A {
295     ///     fn a(&self) -> &str{
296     ///         &self.a
297     ///     }
298     /// }
299     /// ```
300     #[clippy::version = "1.67.0"]
301     pub MISNAMED_GETTERS,
302     suspicious,
303     "getter method returning the wrong field"
304 }
305
306 #[derive(Copy, Clone)]
307 pub struct Functions {
308     too_many_arguments_threshold: u64,
309     too_many_lines_threshold: u64,
310     large_error_threshold: u64,
311 }
312
313 impl Functions {
314     pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64) -> Self {
315         Self {
316             too_many_arguments_threshold,
317             too_many_lines_threshold,
318             large_error_threshold,
319         }
320     }
321 }
322
323 impl_lint_pass!(Functions => [
324     TOO_MANY_ARGUMENTS,
325     TOO_MANY_LINES,
326     NOT_UNSAFE_PTR_ARG_DEREF,
327     MUST_USE_UNIT,
328     DOUBLE_MUST_USE,
329     MUST_USE_CANDIDATE,
330     RESULT_UNIT_ERR,
331     RESULT_LARGE_ERR,
332     MISNAMED_GETTERS,
333 ]);
334
335 impl<'tcx> LateLintPass<'tcx> for Functions {
336     fn check_fn(
337         &mut self,
338         cx: &LateContext<'tcx>,
339         kind: intravisit::FnKind<'tcx>,
340         decl: &'tcx hir::FnDecl<'_>,
341         body: &'tcx hir::Body<'_>,
342         span: Span,
343         hir_id: hir::HirId,
344     ) {
345         too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold);
346         too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold);
347         not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, hir_id);
348         misnamed_getters::check_fn(cx, kind, decl, body, span, hir_id);
349     }
350
351     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
352         must_use::check_item(cx, item);
353         result::check_item(cx, item, self.large_error_threshold);
354     }
355
356     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
357         must_use::check_impl_item(cx, item);
358         result::check_impl_item(cx, item, self.large_error_threshold);
359     }
360
361     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
362         too_many_arguments::check_trait_item(cx, item, self.too_many_arguments_threshold);
363         not_unsafe_ptr_arg_deref::check_trait_item(cx, item);
364         must_use::check_trait_item(cx, item);
365         result::check_trait_item(cx, item, self.large_error_threshold);
366     }
367 }