Skip to content
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 lints around#[must_use] #4560

Merged
merged 1 commit into from
Oct 14, 2019
Merged

new lints around#[must_use] #4560

merged 1 commit into from
Oct 14, 2019

Conversation

llogiq
Copy link
Contributor

@llogiq llogiq commented Sep 20, 2019

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

@llogiq llogiq force-pushed the must-use-pure branch 8 times, most recently from 845f4af to a59abf3 Compare September 22, 2019 07:17
Copy link
Member

@phansch phansch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an initial review, I think this could use a second pair of eyes, too :)

Oh, and also a util/dev fmt was missing

tests/ui/must_use_unit.rs Show resolved Hide resolved
clippy_lints/src/functions.rs Outdated Show resolved Hide resolved
if let hir::ImplItemKind::Method(..) = item.node {
self.depth = self.depth.saturating_sub(1);
}
}
}

impl<'a, 'tcx> Functions {
fn check_arg_number(self, cx: &LateContext<'_, '_>, decl: &hir::FnDecl, span: Span) {
// Remove the function body from the span. We can't use `SourceMap::def_span` because the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this comment can now be removed or should be moved to the doc comment of function_header_span?

README.md Outdated Show resolved Hide resolved
LL | pub fn pure(i: u8) -> u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn pure(i: u8) -> u8`
|
= note: `-D clippy::pure-without-must-use` implied by `-D warnings`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to have more pure function examples that trigger the lint. Does it trigger in pure trait methods, for example?

@llogiq
Copy link
Contributor Author

llogiq commented Sep 22, 2019

The error seems unrelated? Perhaps a Rust PR that changed the error output.

@phansch
Copy link
Member

phansch commented Sep 22, 2019

The error seems unrelated? Perhaps a Rust PR that changed the error output.

Yup, that was fixed by #4565

@llogiq
Copy link
Contributor Author

llogiq commented Sep 23, 2019

I adressed your comments, @phansch. Thank you for the thorough review.

Copy link
Member

@flip1995 flip1995 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Impl LGTM. As @phansch said, a few more tests would be great. I think the code path of mutates_static() == true is never hit by the tests?

clippy_lints/src/functions.rs Outdated Show resolved Hide resolved
@llogiq
Copy link
Contributor Author

llogiq commented Sep 23, 2019

Added the tests and fixed the doc nit.

CHANGELOG.md Show resolved Hide resolved
clippy_lints/src/functions.rs Outdated Show resolved Hide resolved
clippy_lints/src/functions.rs Outdated Show resolved Hide resolved
@Centril
Copy link
Contributor

Centril commented Sep 23, 2019

I think this PR advocates a rather strange definition of "pure" which is not referentially transparent nor even deterministic. Looking at the diff it seems to have caused a non-trivial amount of false positives, e.g. involving file opening and such. Focusing on mutable types is also not enough, you need to consider side-effects though functions or basic things like println!(). Also, this seems like an analysis that is best done on MIR rather than HIR and should be more like the const fn analyses of the compiler.

@llogiq
Copy link
Contributor Author

llogiq commented Sep 24, 2019

Purity is – perhaps even in FP circles – a nebulous concept. Some people argue that it's about freedom from side effects (yet there is no such thing – any program running on a computer will burn cycles as a side effect, for example), others say they need to be referentially transparent or even deterministic. This lint takes a pragmatic approach. If a function does not mutate a static or its arguments, you'll likely want to call it for its result. I personally don't think file opening is a side effect I'd call a function for if I didn't want to do something with the file.

Also I agree that the lint triggers on a lot of function. Can you point to some you consider false positives?

@ghost
Copy link

ghost commented Sep 24, 2019

This lint shouldn't apply to functions returning Result as you get a rustc warning if you don't use the result anyway.

@ghost
Copy link

ghost commented Sep 24, 2019

Iterator as well. Maybe there is a way to look up if a struct is must_use.

clippy_dev/src/fmt.rs Outdated Show resolved Hide resolved
clippy_dev/src/lib.rs Outdated Show resolved Hide resolved
@Centril
Copy link
Contributor

Centril commented Sep 24, 2019

Purity is – perhaps even in FP circles – a nebulous concept.

See https://pdfs.semanticscholar.org/32ff/28cb5b5c990fe7bdca510040ea22f5c13316.pdf for a well defined definition.

Some people argue that it's about freedom from side effects (yet there is no such thing – any program running on a computer will burn cycles as a side effect, for example),

When reasoning about computer programs we do so preferably considering an idealized abstract machine in which some things (e.g. heat from burning cycles or bit flips due to radiation) are not observable. Otherwise it would be impossible to do all sorts of other reasonings as well (e.g. about soundness).

[...] others say they need to be referentially transparent or even deterministic.

Referentially transparent is a common notion, but a basic property a pure function needs to satisfy is that given f : A → B then ∀ x, y: A. x ≡ y → f(x) ≡ f(y). This is not an operational definition, but is a sufficient yardstick to decide that the functions I've highlighted above are not pure.

This lint takes a pragmatic approach. If a function does not mutate a static or its arguments, you'll likely want to call it for its result.

That's fine; I would suggest renaming the lint to something more suggestive and to extend the "known problems" to note more false positives. In my view, a better, but still pragmatic solution would be to do this on MIR.

I personally don't think file opening is a side effect I'd call a function for if I didn't want to do something with the file.

Merely opening a file is not an interesting side-effect (yet it might cause a problem if the file was already open), but reading it means you are reading the state of the world and that can result in indeterministic results.

@llogiq
Copy link
Contributor Author

llogiq commented Sep 24, 2019

@Centril I see what you mean now. I'll best implement @mikerite's suggestion and rename the lint to must_use_candidate. It's already a pedantic lint, so false positives are somewhat acceptable.

@phansch phansch added the S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) label Sep 25, 2019
@llogiq llogiq changed the title new lint for missing #[must_use] on pure fns new lint for missing #[must_use] on suitable fns Sep 25, 2019
@llogiq
Copy link
Contributor Author

llogiq commented Oct 11, 2019

@phansch I've added your test case as-is and also added in_external_macro checks to must_use_candidate and double_must_use. Unfortunately, CI is broken again, we need yet another rustup.

@phansch
Copy link
Member

phansch commented Oct 12, 2019

isn't that missing a #[must_use] annotation for foo()

oh, yes! 😅

Also why would we want to quell the lint in macros?

The test is just there to check that we don't lint occurences in external macros. It should still lint for non-external macros.

Copy link
Member

@phansch phansch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left two comments and I believe there are also two open comments from @sinkuu that are only visible in the changes tab?

Apart from that it looks good to me 👍

clippy_lints/src/functions.rs Show resolved Hide resolved
clippy_lints/src/functions.rs Show resolved Hide resolved
@llogiq
Copy link
Contributor Author

llogiq commented Oct 13, 2019

Let's see what CI thinks about it. I may need yet another rebase though.

@llogiq llogiq force-pushed the must-use-pure branch 3 times, most recently from b9785b3 to 80f342b Compare October 14, 2019 07:29
`must_use_unit` lints unit-returning functions with a `#[must_use]`
attribute, suggesting to remove it.

`double_must_use` lints functions with a plain `#[must_use]`
attribute, but which return a type which is already `#[must_use]`,
so the attribute has no benefit.

`must_use_candidate` is a pedantic lint that lints functions and
methods that return some non-unit type that is not already
`#[must_use]` and suggests to add the annotation.
@llogiq
Copy link
Contributor Author

llogiq commented Oct 14, 2019

@phansch r?

@phansch
Copy link
Member

phansch commented Oct 14, 2019

@bors r+ nice!

@bors
Copy link
Collaborator

bors commented Oct 14, 2019

📌 Commit cc62260 has been approved by phansch

@bors

This comment has been minimized.

bors added a commit that referenced this pull request Oct 14, 2019
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
@phansch
Copy link
Member

phansch commented Oct 14, 2019

@bors retry (yielding priority to #4663)

@bors

This comment has been minimized.

bors added a commit that referenced this pull request Oct 14, 2019
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
@phansch
Copy link
Member

phansch commented Oct 14, 2019

@bors retry

@bors
Copy link
Collaborator

bors commented Oct 14, 2019

⌛ Testing commit cc62260 with merge 8fae2dd...

bors added a commit that referenced this pull request Oct 14, 2019
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
@bors
Copy link
Collaborator

bors commented Oct 14, 2019

☀️ Test successful - checks-travis, status-appveyor
Approved by: phansch
Pushing 8fae2dd to master...

@llogiq
Copy link
Contributor Author

llogiq commented Oct 14, 2019

Thanks, @phansch!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties
Projects
None yet
Development

Successfully merging this pull request may close these issues.

New lint: pure functions without #[must_use]
6 participants