-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New lint: pure functions without #[must_use]
#4526
Comments
I would also exclude functions that have an |
Wrt unsafe, that feels a bit random. If you call another safe function that does the unsafe for you it won't be triggered. |
I think for a lint like this to not produce lots of false-positives, it would need to be more clever than having a blacklist of mutable / interior-mutable types. Interior mutability is often not obvious from function signatures alone. There's gtk for example, where most / all widget types have |
Agreed, I'd also mark callables as impure. Even then the lint is likely to produce some false positives, but as a pedantic lint it might still be useful. I'm thinking about omitting the lint for inner functions/methods, because the locality will make errors of that kind unlikely, so the attribute won't give too much benefit. In other news, I'll be working on this. |
Not sure how much access clippy has to type information, but if "mutable arguments" could be implemented in terms of
Why though? Higher-order functions are used most often in functional-style programming, which I'd say could in turn benefit most often from this lint. |
Because the argument may itself be impure, thus calling the function may have side effects by calling its argument. |
Yeah I guess as a conservative start, higher-order functions could be excluded altogether. Still I'm wondering if there isn't some way to reason about function arguments that would make it possible to apply this lint to something like this: fn somefn<T, F>(mut f: F, mut val: T) -> u32
where
F: FnMut(T) -> Option<T>,
{
let mut count = 0;
while let Some(v) = f(val) {
val = v;
count += 1;
}
count
} Because while obviously this function could be used just for its side effects, that doesn't seem like something anybody would do. IMO this function's return value it what gives it meaning. And I think a human writer would most likely add |
new lints around`#[must_use]` changelog: Add `must_use_candidate` lint, add `must-use-unit` lint, add `double_must_use` lint The first one checks if an public function or method has no mutable argument and mutates no non-local data and lints if it has no `#[must_use]` attribute. It will skip inner functions, because those are usually highly local and the attribute doesn't have as much benefit there. The second lints `#[must_use]` attributes on functions and methods that return unit. Those attributes are likely a remnant from a refactoring that removed the return value. The last one lints for `#[must_use]` attributrs without text on functions that return a type which is already marked `#[must_use]`. This has no auto-suggestion, because while it would be easy to do, there may be value in writing a detailed text for the attribute instead. This fixes #4526
new lints around`#[must_use]` changelog: Add `must_use_candidate` lint, add `must-use-unit` lint, add `double_must_use` lint The first one checks if an public function or method has no mutable argument and mutates no non-local data and lints if it has no `#[must_use]` attribute. It will skip inner functions, because those are usually highly local and the attribute doesn't have as much benefit there. The second lints `#[must_use]` attributes on functions and methods that return unit. Those attributes are likely a remnant from a refactoring that removed the return value. The last one lints for `#[must_use]` attributrs without text on functions that return a type which is already marked `#[must_use]`. This has no auto-suggestion, because while it would be easy to do, there may be value in writing a detailed text for the attribute instead. This fixes #4526
I often see rust PRs that mark pure functions as
#[must_use]
, which makes sense, as discarding their results will more often than not be in error. As#[must_use]
is now available for user code, we may want to lint functions that should have them.To make this lintable at all, we need to first define "pure":
A pure function has no mutable argument and does not mutate global state.
Arguments that are mutable:
&mut _
,&Atomic*
,&UnsafeCell
,&Cell*
,&RefCell*
,&Mutex<_>
,&RwLock<_>
,&Sender
,&Receiver
Mutating global state can be done via
*Assign
ops whereself
isstatic mut
, direct assignment to astatic mut
or calling a method on astatic mut
that takes&mut self
. For simplicity, it should suffice if we match those operations on anything that is not local to the body (or the args).The text was updated successfully, but these errors were encountered: