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