Auto merge of #115183 - flip1995:clippyup, r=Manishearth,oli-obk

Update Clippy

r? `@oli-obk` Assigning you, because something broke with ui_test:

```
tests/ui/crashes/ice-7272.rs FAILED:
command: "<unknown>"

A bug in `ui_test` occurred: called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }

full stderr:

```

(and that 103 times)

Thought I would ping you, before starting to investigate. Maybe you know what's going on.
This commit is contained in:
bors 2023-08-29 17:03:26 +00:00
commit af02b43015
1885 changed files with 16712 additions and 9889 deletions

View file

@ -6,18 +6,105 @@ document.
## Unreleased / Beta / In Rust Nightly
[435a8ad8...master](https://github.com/rust-lang/rust-clippy/compare/435a8ad8...master)
[37f4c172...master](https://github.com/rust-lang/rust-clippy/compare/37f4c172...master)
## Rust 1.72
Current stable, released 2023-08-24
[View all 131 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-05-22T14%3A53%3A59Z..2023-07-01T22%3A57%3A20Z+base%3Amaster)
### New Lints
* [`manual_try_fold`]
[#11012](https://github.com/rust-lang/rust-clippy/pull/11012)
* [`tuple_array_conversions`]
[#11020](https://github.com/rust-lang/rust-clippy/pull/11020)
* [`redundant_at_rest_pattern`]
[#11013](https://github.com/rust-lang/rust-clippy/pull/11013)
* [`needless_pub_self`]
[#10967](https://github.com/rust-lang/rust-clippy/pull/10967)
* [`pub_with_shorthand`]
[#10967](https://github.com/rust-lang/rust-clippy/pull/10967)
* [`pub_without_shorthand`]
[#10967](https://github.com/rust-lang/rust-clippy/pull/10967)
* [`manual_range_patterns`]
[#10968](https://github.com/rust-lang/rust-clippy/pull/10968)
* [`needless_raw_string_hashes`]
[#10884](https://github.com/rust-lang/rust-clippy/pull/10884)
* [`needless_raw_strings`]
[#10884](https://github.com/rust-lang/rust-clippy/pull/10884)
* [`incorrect_clone_impl_on_copy_type`]
[#10925](https://github.com/rust-lang/rust-clippy/pull/10925)
* [`drain_collect`]
[#10835](https://github.com/rust-lang/rust-clippy/pull/10835)
* [`single_range_in_vec_init`]
[#10934](https://github.com/rust-lang/rust-clippy/pull/10934)
* [`unnecessary_literal_unwrap`]
[#10358](https://github.com/rust-lang/rust-clippy/pull/10358)
* [`large_stack_frames`]
[#10827](https://github.com/rust-lang/rust-clippy/pull/10827)
* [`min_ident_chars`]
[#10916](https://github.com/rust-lang/rust-clippy/pull/10916)
* [`needless_if`]
[#10921](https://github.com/rust-lang/rust-clippy/pull/10921)
* [`excessive_nesting`]
[#10672](https://github.com/rust-lang/rust-clippy/pull/10672)
* [`arc_with_non_send_sync`]
[#10898](https://github.com/rust-lang/rust-clippy/pull/10898)
* [`redundant_type_annotations`]
[#10570](https://github.com/rust-lang/rust-clippy/pull/10570)
* [`host_endian_bytes`]
[#10826](https://github.com/rust-lang/rust-clippy/pull/10826)
* [`little_endian_bytes`]
[#10826](https://github.com/rust-lang/rust-clippy/pull/10826)
* [`big_endian_bytes`]
[#10826](https://github.com/rust-lang/rust-clippy/pull/10826)
* [`ptr_cast_constness`]
[#10779](https://github.com/rust-lang/rust-clippy/pull/10779)
* [`needless_else`]
[#10810](https://github.com/rust-lang/rust-clippy/pull/10810)
### Moves and Deprecations
* Moved [`redundant_clone`] to `nursery` (Now allow-by-default)
[#10873](https://github.com/rust-lang/rust-clippy/pull/10873)
### Enhancements
* [`undocumented_unsafe_blocks`]: Added [`accept-comment-above-attributes`] configuration
[#10986](https://github.com/rust-lang/rust-clippy/pull/10986)
* [`undocumented_unsafe_blocks`]: Added [`accept-comment-above-statement`] configuration.
[#10886](https://github.com/rust-lang/rust-clippy/pull/10886)
* [`missing_panics_doc`]: No longer lints on `todo!()`
[#10976](https://github.com/rust-lang/rust-clippy/pull/10976)
* [`module_inception`]: Added `allow-private-module-inception` configuration.
[#10917](https://github.com/rust-lang/rust-clippy/pull/10917)
* Errors and warnings generated while parsing `clippy.toml` now point to the location in the TOML
file the error/warning occurred in.
[#10607](https://github.com/rust-lang/rust-clippy/pull/10607)
### False Positive Fixes
* [`excessive_precision`]: No longer lints overflowing literals
[#10952](https://github.com/rust-lang/rust-clippy/pull/10952)
### Suggestion Fixes/Improvements
* [`option_map_unwrap_or`]: The suggestion now considers the set [`msrv`] config value
[#11030](https://github.com/rust-lang/rust-clippy/pull/11030)
### Documentation Improvements
* [Clippy's lint list] now stores filter parameters in the URL, to allow easy sharing
[#10834](https://github.com/rust-lang/rust-clippy/pull/10834)
## Rust 1.71
Current stable, released 2023-07-13
Released 2023-07-13
<!-- FIXME: Remove the request for feedback, with the next changelog -->
We're trying out a new shorter changelog format, that only contains significant changes.
You can check out the list of merged pull requests for a list of all changes.
If you have any feedback related to the new format, please share it in
[#10847](https://github.com/rust-lang/rust-clippy/issues/10847)
Note: Clippy will use a shorter changelog format from now on, if you want a detailed list of
all changes, please check out the list of merged pull requests.
[View all 78 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-04-11T20%3A05%3A26Z..2023-05-20T13%3A48%3A17Z+base%3Amaster)
@ -4677,6 +4764,7 @@ Released 2018-09-13
[pull3665]: https://github.com/rust-lang/rust-clippy/pull/3665
[adding_lints]: https://github.com/rust-lang/rust-clippy/blob/master/book/src/development/adding_lints.md
[`README.md`]: https://github.com/rust-lang/rust-clippy/blob/master/README.md
[Clippy's lint list]: https://rust-lang.github.io/rust-clippy/master/index.html
<!-- lint disable no-unused-definitions -->
<!-- begin autogenerated links to lint list -->
@ -4897,6 +4985,7 @@ Released 2018-09-13
[`implicit_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_return
[`implicit_saturating_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_add
[`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub
[`implied_bounds_in_impls`]: https://rust-lang.github.io/rust-clippy/master/index.html#implied_bounds_in_impls
[`impossible_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#impossible_comparisons
[`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
[`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
@ -5211,6 +5300,7 @@ Released 2018-09-13
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
[`reserve_after_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#reserve_after_initialization
[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
[`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used
[`result_large_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err
@ -5241,6 +5331,7 @@ Released 2018-09-13
[`short_circuit_statement`]: https://rust-lang.github.io/rust-clippy/master/index.html#short_circuit_statement
[`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq
[`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
[`should_panic_without_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_panic_without_expect
[`significant_drop_in_scrutinee`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_in_scrutinee
[`significant_drop_tightening`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_tightening
[`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names

View file

@ -148,7 +148,7 @@ pub mod else_if_without_else;
pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
// ...
store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
// ...
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![

View file

@ -1,6 +1,6 @@
[package]
name = "clippy"
version = "0.1.73"
version = "0.1.74"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@ -27,7 +27,7 @@ tempfile = { version = "3.2", optional = true }
termize = "0.1"
[dev-dependencies]
ui_test = "0.11.5"
ui_test = "0.18.1"
tester = "0.9"
regex = "1.5"
toml = "0.7.3"

View file

@ -13,8 +13,10 @@
- [Development](development/README.md)
- [Basics](development/basics.md)
- [Adding Lints](development/adding_lints.md)
- [Defining Lints](development/defining_lints.md)
- [Lint Passes](development/lint_passes.md)
- [Type Checking](development/type_checking.md)
- [Method Checking](development/method_checking.md)
- [Macro Expansions](development/macro_expansions.md)
- [Common Tools](development/common_tools_writing_lints.md)
- [Infrastructure](development/infrastructure/README.md)

View file

@ -161,8 +161,8 @@ The process of generating the `.stderr` file is the same, and prepending the
## Rustfix tests
If the lint you are working on is making use of structured suggestions, the test
file should include a `//@run-rustfix` comment at the top. This will
additionally run [rustfix] for that test. Rustfix will apply the suggestions
will create a `.fixed` file by running [rustfix] for that test.
Rustfix will apply the suggestions
from the lint to the code of the test file and compare that to the contents of a
`.fixed` file.

View file

@ -0,0 +1,205 @@
# Define New Lints
The first step in the journey of a new lint is the definition
and registration of the lint in Clippy's codebase.
We can use the Clippy dev tools to handle this step since setting up the
lint involves some boilerplate code.
#### Lint types
A lint type is the category of items and expressions in which your lint focuses on.
As of the writing of this documentation update, there are 12 _types_ of lints
besides the numerous standalone lints living under `clippy_lints/src/`:
- `cargo`
- `casts`
- `functions`
- `loops`
- `matches`
- `methods`
- `misc_early`
- `operators`
- `transmute`
- `types`
- `unit_types`
- `utils / internal` (Clippy internal lints)
These types group together lints that share some common behaviors. For instance,
`functions` groups together lints that deal with some aspects of functions in
Rust, like definitions, signatures and attributes.
For more information, feel free to compare the lint files under any category
with [All Clippy lints][all_lints] or ask one of the maintainers.
## Lint name
A good lint name is important, make sure to check the [lint naming
guidelines][lint_naming]. Don't worry, if the lint name doesn't fit, a Clippy
team member will alert you in the PR process.
---
We'll name our example lint that detects functions named "foo" `foo_functions`.
Check the [lint naming guidelines][lint_naming] to see why this name makes
sense.
## Add and Register the Lint
Now that a name is chosen, we shall register `foo_functions` as a lint to the
codebase. There are two ways to register a lint.
### Standalone
If you believe that this new lint is a standalone lint (that doesn't belong to
any specific [type](#lint-types) like `functions` or `loops`), you can run the
following command in your Clippy project:
```sh
$ cargo dev new_lint --name=lint_name --pass=late --category=pedantic
```
There are two things to note here:
1. `--pass`: We set `--pass=late` in this command to do a late lint pass. The
alternative is an `early` lint pass. We will discuss this difference in a
later chapter.
<!-- FIXME: Link that "later chapter" when lint_passes.md is merged -->
2. `--category`: If not provided, the `category` of this new lint will default
to `nursery`.
The `cargo dev new_lint` command will create a new file:
`clippy_lints/src/foo_functions.rs` as well as [register the
lint](#lint-registration).
Overall, you should notice that the following files are modified or created:
```sh
$ git status
On branch foo_functions
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: CHANGELOG.md
modified: clippy_lints/src/lib.register_lints.rs
modified: clippy_lints/src/lib.register_pedantic.rs
modified: clippy_lints/src/lib.rs
Untracked files:
(use "git add <file>..." to include in what will be committed)
clippy_lints/src/foo_functions.rs
tests/ui/foo_functions.rs
```
### Specific Type
> **Note**: Lint types are listed in the ["Lint types"](#lint-types) section
If you believe that this new lint belongs to a specific type of lints,
you can run `cargo dev new_lint` with a `--type` option.
Since our `foo_functions` lint is related to function calls, one could
argue that we should put it into a group of lints that detect some behaviors
of functions, we can put it in the `functions` group.
Let's run the following command in your Clippy project:
```sh
$ cargo dev new_lint --name=foo_functions --type=functions --category=pedantic
```
This command will create, among other things, a new file:
`clippy_lints/src/{type}/foo_functions.rs`.
In our case, the path will be `clippy_lints/src/functions/foo_functions.rs`.
Notice how this command has a `--type` flag instead of `--pass`. Unlike a standalone
definition, this lint won't be registered in the traditional sense. Instead, you will
call your lint from within the type's lint pass, found in `clippy_lints/src/{type}/mod.rs`.
A _type_ is just the name of a directory in `clippy_lints/src`, like `functions` in
the example command. Clippy groups together some lints that share common behaviors,
so if your lint falls into one, it would be best to add it to that type.
Overall, you should notice that the following files are modified or created:
```sh
$ git status
On branch foo_functions
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: CHANGELOG.md
modified: clippy_lints/src/declared_lints.rs
modified: clippy_lints/src/functions/mod.rs
Untracked files:
(use "git add <file>..." to include in what will be committed)
clippy_lints/src/functions/foo_functions.rs
tests/ui/foo_functions.rs
```
## The `define_clippy_lints` macro
After `cargo dev new_lint`, you should see a macro with the name
`define_clippy_lints`. It will be in the same file if you defined a standalone
lint, and it will be in `mod.rs` if you defined a type-specific lint.
The macro looks something like this:
```rust
declare_clippy_lint! {
/// ### What it does
///
/// // Describe here what does the lint do.
///
/// Triggers when detects...
///
/// ### Why is this bad?
///
/// // Describe why this pattern would be bad
///
/// It can lead to...
///
/// ### Example
/// ```rust
/// // example code where clippy issues a warning
/// ```
/// Use instead:
/// ```rust
/// // example code which does not raise clippy warning
/// ```
#[clippy::version = "1.70.0"] // <- In which version was this implemented, keep it up to date!
pub LINT_NAME, // <- The lint name IN_ALL_CAPS
pedantic, // <- The lint group
"default lint description" // <- A lint description, e.g. "A function has an unit return type."
}
```
## Lint registration
If we run the `cargo dev new_lint` command for a new lint, the lint will be
automatically registered and there is nothing more to do.
However, sometimes we might want to declare a new lint by hand. In this case,
we'd use `cargo dev update_lints` command afterwards.
When a lint is manually declared, we might need to register the lint pass
manually in the `register_plugins` function in `clippy_lints/src/lib.rs`:
```rust
store.register_late_pass(|_| Box::new(foo_functions::FooFunctions));
```
As you might have guessed, where there's something late, there is something
early: in Clippy there is a `register_early_pass` method as well. More on early
vs. late passes in a later chapter.
<!-- FIXME: Link that "later chapter" when lint_passes.md is merged -->
Without a call to one of `register_early_pass` or `register_late_pass`, the lint
pass in question will not be run.
[all_lints]: https://rust-lang.github.io/rust-clippy/master/
[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints

View file

@ -0,0 +1,93 @@
# Method Checking
In some scenarios we might want to check for methods when developing
a lint. There are two kinds of questions that we might be curious about:
- Invocation: Does an expression call a specific method?
- Definition: Does an `impl` define a method?
## Checking if an `expr` is calling a specific method
Suppose we have an `expr`, we can check whether it calls a specific
method, e.g. `our_fancy_method`, by performing a pattern match on
the [`ExprKind`] that we can access from `expr.kind`:
```rust
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_span::sym;
use clippy_utils::is_trait_method;
impl<'tcx> LateLintPass<'tcx> for OurFancyMethodLint {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
// Check our expr is calling a method with pattern matching
if let hir::ExprKind::MethodCall(path, _, [self_arg, ..]) = &expr.kind
// Check if the name of this method is `our_fancy_method`
&& path.ident.name == sym!(our_fancy_method)
// We can check the type of the self argument whenever necessary.
// (It's necessary if we want to check that method is specifically belonging to a specific trait,
// for example, a `map` method could belong to user-defined trait instead of to `Iterator`)
// See the next section for more information.
&& is_trait_method(cx, self_arg, sym::OurFancyTrait)
{
println!("`expr` is a method call for `our_fancy_method`");
}
}
}
```
Take a closer look at the `ExprKind` enum variant [`MethodCall`] for more
information on the pattern matching. As mentioned in [Define
Lints](defining_lints.md#lint-types), the `methods` lint type is full of pattern
matching with `MethodCall` in case the reader wishes to explore more.
Additionally, we use the [`clippy_utils::sym!`][sym] macro to conveniently
convert an input `our_fancy_method` into a `Symbol` and compare that symbol to
the [`Ident`]'s name in the [`PathSegment`] in the [`MethodCall`].
## Checking if a `impl` block implements a method
While sometimes we want to check whether a method is being called or not, other
times we want to know if our `Ty` defines a method.
To check if our `impl` block defines a method `our_fancy_method`, we will
utilize the [`check_impl_item`] method that is available in our beloved
[`LateLintPass`] (for more information, refer to the ["Lint
Passes"](lint_passes.md) chapter in the Clippy book). This method provides us
with an [`ImplItem`] struct, which represents anything within an `impl` block.
Let us take a look at how we might check for the implementation of
`our_fancy_method` on a type:
```rust
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::return_ty;
use rustc_hir::{ImplItem, ImplItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_span::symbol::sym;
impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
// Check if item is a method/function
if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
// Check the method is named `our_fancy_method`
&& impl_item.ident.name == sym!(our_fancy_method)
// We can also check it has a parameter `self`
&& signature.decl.implicit_self.has_implicit_self()
// We can go even further and even check if its return type is `String`
&& is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::String)
{
println!("`our_fancy_method` is implemented!");
}
}
}
```
[`check_impl_item`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_lint/trait.LateLintPass.html#method.check_impl_item
[`ExprKind`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/hir/enum.ExprKind.html
[`Ident`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_span/symbol/struct.Ident.html
[`ImplItem`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_hir/hir/struct.ImplItem.html
[`LateLintPass`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_lint/trait.LateLintPass.html
[`MethodCall`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/hir/enum.ExprKind.html#variant.MethodCall
[`PathSegment`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/hir/struct.PathSegment.html
[sym]: https://doc.rust-lang.org/stable/nightly-rustc/clippy_utils/macro.sym.html

View file

@ -9,16 +9,12 @@ accessed by the `SPEEDTEST` (and `SPEEDTEST_*`) environment variables.
To do a simple speed test of a lint (e.g. `allow_attributes`), use this command.
```sh
$ SPEEDTEST=ui TESTNAME="allow_attributes" cargo uitest -- --nocapture
$ SPEEDTEST=ui TESTNAME="allow_attributes" cargo uitest
```
This will test all `ui` tests (`SPEEDTEST=ui`) whose names start with `allow_attributes`. By default, `SPEEDTEST` will
iterate your test 1000 times. But you can change this with `SPEEDTEST_ITERATIONS`.
```sh
$ SPEEDTEST=toml SPEEDTEST_ITERATIONS=100 TESTNAME="semicolon_block" cargo uitest -- --nocapture
$ SPEEDTEST=toml SPEEDTEST_ITERATIONS=100 TESTNAME="semicolon_block" cargo uitest
```
> **WARNING**: Be sure to use `-- --nocapture` at the end of the command to see the average test time. If you don't
> use `-- --nocapture` (e.g. `SPEEDTEST=ui` `TESTNAME="let_underscore_untyped" cargo uitest -- --nocapture`), this
> will not show up.

View file

@ -690,7 +690,6 @@ fn gen_deprecated_lints_test(lints: &[DeprecatedLint]) -> String {
fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String {
let mut seen_lints = HashSet::new();
let mut res: String = GENERATED_FILE_COMMENT.into();
res.push_str("//@run-rustfix\n\n");
for lint in lints {
if seen_lints.insert(&lint.new_name) {
writeln!(res, "#![allow({})]", lint.new_name).unwrap();

View file

@ -1,6 +1,6 @@
[package]
name = "clippy_lints"
version = "0.1.73"
version = "0.1.74"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"

View file

@ -6,7 +6,11 @@ use clippy_utils::macros::{is_panic, macro_backtrace};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
use if_chain::if_chain;
use rustc_ast::{AttrKind, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
use rustc_ast::token::{Token, TokenKind};
use rustc_ast::tokenstream::TokenTree;
use rustc_ast::{
AttrArgs, AttrArgsEq, AttrKind, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem,
};
use rustc_errors::Applicability;
use rustc_hir::{
Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
@ -339,6 +343,41 @@ declare_clippy_lint! {
"ensures that all `allow` and `expect` attributes have a reason"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for `#[should_panic]` attributes without specifying the expected panic message.
///
/// ### Why is this bad?
/// The expected panic message should be specified to ensure that the test is actually
/// panicking with the expected message, and not another unrelated panic.
///
/// ### Example
/// ```rust
/// fn random() -> i32 { 0 }
///
/// #[should_panic]
/// #[test]
/// fn my_test() {
/// let _ = 1 / random();
/// }
/// ```
///
/// Use instead:
/// ```rust
/// fn random() -> i32 { 0 }
///
/// #[should_panic = "attempt to divide by zero"]
/// #[test]
/// fn my_test() {
/// let _ = 1 / random();
/// }
/// ```
#[clippy::version = "1.73.0"]
pub SHOULD_PANIC_WITHOUT_EXPECT,
pedantic,
"ensures that all `should_panic` attributes specify its expected panic message"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for `any` and `all` combinators in `cfg` with only one condition.
@ -395,6 +434,7 @@ declare_lint_pass!(Attributes => [
DEPRECATED_SEMVER,
USELESS_ATTRIBUTE,
BLANKET_CLIPPY_RESTRICTION_LINTS,
SHOULD_PANIC_WITHOUT_EXPECT,
]);
impl<'tcx> LateLintPass<'tcx> for Attributes {
@ -442,6 +482,9 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
}
}
}
if attr.has_name(sym::should_panic) {
check_should_panic_reason(cx, attr);
}
}
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
@ -550,6 +593,35 @@ fn extract_clippy_lint(lint: &NestedMetaItem) -> Option<Symbol> {
None
}
fn check_should_panic_reason(cx: &LateContext<'_>, attr: &Attribute) {
if let AttrKind::Normal(normal_attr) = &attr.kind {
if let AttrArgs::Eq(_, AttrArgsEq::Hir(_)) = &normal_attr.item.args {
// `#[should_panic = ".."]` found, good
return;
}
if let AttrArgs::Delimited(args) = &normal_attr.item.args
&& let mut tt_iter = args.tokens.trees()
&& let Some(TokenTree::Token(Token { kind: TokenKind::Ident(sym::expected, _), .. }, _)) = tt_iter.next()
&& let Some(TokenTree::Token(Token { kind: TokenKind::Eq, .. }, _)) = tt_iter.next()
&& let Some(TokenTree::Token(Token { kind: TokenKind::Literal(_), .. }, _)) = tt_iter.next()
{
// `#[should_panic(expected = "..")]` found, good
return;
}
span_lint_and_sugg(
cx,
SHOULD_PANIC_WITHOUT_EXPECT,
attr.span,
"#[should_panic] attribute without a reason",
"consider specifying the expected panic",
r#"#[should_panic(expected = /* panic message */)]"#.into(),
Applicability::HasPlaceholders,
);
}
}
fn check_clippy_lint_names(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem]) {
for lint in items {
if let Some(lint_name) = extract_clippy_lint(lint) {

View file

@ -5,6 +5,7 @@ use rustc_hir::{Expr, ExprKind, GenericArg};
use rustc_lint::LateContext;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty};
use rustc_span::sym;
use super::CAST_PTR_ALIGNMENT;
@ -76,13 +77,14 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
ExprKind::Call(func, [arg, ..]) if arg.hir_id == e.hir_id => {
static PATHS: &[&[&str]] = &[
paths::PTR_READ_UNALIGNED.as_slice(),
paths::PTR_WRITE_UNALIGNED.as_slice(),
paths::PTR_UNALIGNED_VOLATILE_LOAD.as_slice(),
paths::PTR_UNALIGNED_VOLATILE_STORE.as_slice(),
];
if let ExprKind::Path(path) = &func.kind
&& let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
&& match_any_def_paths(cx, def_id, PATHS).is_some()
&& (match_any_def_paths(cx, def_id, PATHS).is_some()
|| cx.tcx.is_diagnostic_item(sym::ptr_write_unaligned, def_id))
{
true
} else {

View file

@ -418,7 +418,7 @@ declare_clippy_lint! {
/// let mut_ptr = ptr.cast_mut();
/// let ptr = mut_ptr.cast_const();
/// ```
#[clippy::version = "1.71.0"]
#[clippy::version = "1.72.0"]
pub PTR_CAST_CONSTNESS,
pedantic,
"casting using `as` from and to raw pointers to change constness when specialized methods apply"

View file

@ -58,6 +58,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::attrs::MAYBE_MISUSED_CFG_INFO,
crate::attrs::MISMATCHED_TARGET_OS_INFO,
crate::attrs::NON_MINIMAL_CFG_INFO,
crate::attrs::SHOULD_PANIC_WITHOUT_EXPECT_INFO,
crate::attrs::USELESS_ATTRIBUTE_INFO,
crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO,
crate::await_holding_invalid::AWAIT_HOLDING_LOCK_INFO,
@ -208,6 +209,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::implicit_return::IMPLICIT_RETURN_INFO,
crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO,
crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO,
crate::implied_bounds_in_impls::IMPLIED_BOUNDS_IN_IMPLS_INFO,
crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO,
crate::incorrect_impls::INCORRECT_CLONE_IMPL_ON_COPY_TYPE_INFO,
crate::incorrect_impls::INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE_INFO,
@ -578,6 +580,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::reference::DEREF_ADDROF_INFO,
crate::regex::INVALID_REGEX_INFO,
crate::regex::TRIVIAL_REGEX_INFO,
crate::reserve_after_initialization::RESERVE_AFTER_INITIALIZATION_INFO,
crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
crate::returns::LET_AND_RETURN_INFO,
crate::returns::NEEDLESS_RETURN_INFO,

View file

@ -21,7 +21,7 @@ declare_clippy_lint! {
/// let _x = 2i32.to_ne_bytes();
/// let _y = 2i64.to_ne_bytes();
/// ```
#[clippy::version = "1.71.0"]
#[clippy::version = "1.72.0"]
pub HOST_ENDIAN_BYTES,
restriction,
"disallows usage of the `to_ne_bytes` method"
@ -40,7 +40,7 @@ declare_clippy_lint! {
/// let _x = 2i32.to_le_bytes();
/// let _y = 2i64.to_le_bytes();
/// ```
#[clippy::version = "1.71.0"]
#[clippy::version = "1.72.0"]
pub LITTLE_ENDIAN_BYTES,
restriction,
"disallows usage of the `to_le_bytes` method"
@ -59,7 +59,7 @@ declare_clippy_lint! {
/// let _x = 2i32.to_be_bytes();
/// let _y = 2i64.to_be_bytes();
/// ```
#[clippy::version = "1.71.0"]
#[clippy::version = "1.72.0"]
pub BIG_ENDIAN_BYTES,
restriction,
"disallows usage of the `to_be_bytes` method"

View file

@ -56,7 +56,7 @@ declare_clippy_lint! {
/// // lib.rs
/// pub mod a;
/// ```
#[clippy::version = "1.70.0"]
#[clippy::version = "1.72.0"]
pub EXCESSIVE_NESTING,
complexity,
"checks for blocks nested beyond a certain threshold"

View file

@ -0,0 +1,202 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use rustc_errors::{Applicability, SuggestionStyle};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
Body, FnDecl, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind, ItemKind, TraitBoundModifier, TraitItem,
TraitItemKind, TyKind,
};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, ClauseKind, TyCtxt};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
/// Looks for bounds in `impl Trait` in return position that are implied by other bounds.
/// This can happen when a trait is specified that another trait already has as a supertrait
/// (e.g. `fn() -> impl Deref + DerefMut<Target = i32>` has an unnecessary `Deref` bound,
/// because `Deref` is a supertrait of `DerefMut`)
///
/// ### Why is this bad?
/// Specifying more bounds than necessary adds needless complexity for the reader.
///
/// ### Limitations
/// This lint does not check for implied bounds transitively. Meaning that
/// it does't check for implied bounds from supertraits of supertraits
/// (e.g. `trait A {} trait B: A {} trait C: B {}`, then having an `fn() -> impl A + C`)
///
/// ### Example
/// ```rust
/// # use std::ops::{Deref,DerefMut};
/// fn f() -> impl Deref<Target = i32> + DerefMut<Target = i32> {
/// // ^^^^^^^^^^^^^^^^^^^ unnecessary bound, already implied by the `DerefMut` trait bound
/// Box::new(123)
/// }
/// ```
/// Use instead:
/// ```rust
/// # use std::ops::{Deref,DerefMut};
/// fn f() -> impl DerefMut<Target = i32> {
/// Box::new(123)
/// }
/// ```
#[clippy::version = "1.73.0"]
pub IMPLIED_BOUNDS_IN_IMPLS,
complexity,
"specifying bounds that are implied by other bounds in `impl Trait` type"
}
declare_lint_pass!(ImpliedBoundsInImpls => [IMPLIED_BOUNDS_IN_IMPLS]);
/// This function tries to, for all type parameters in a supertype predicate `GenericTrait<U>`,
/// check if the substituted type in the implied-by bound matches with what's subtituted in the
/// implied type.
///
/// Consider this example.
/// ```rust,ignore
/// trait GenericTrait<T> {}
/// trait GenericSubTrait<T, U, V>: GenericTrait<U> {}
/// ^ trait_predicate_args: [Self#0, U#2]
/// impl GenericTrait<i32> for () {}
/// impl GenericSubTrait<(), i32, ()> for () {}
/// impl GenericSubTrait<(), [u8; 8], ()> for () {}
///
/// fn f() -> impl GenericTrait<i32> + GenericSubTrait<(), [u8; 8], ()> {
/// ^^^ implied_args ^^^^^^^^^^^^^^^ implied_by_args
/// (we are interested in `[u8; 8]` specifically, as that
/// is what `U` in `GenericTrait<U>` is substituted with)
/// ()
/// }
/// ```
/// Here i32 != [u8; 8], so this will return false.
fn is_same_generics(
tcx: TyCtxt<'_>,
trait_predicate_args: &[ty::GenericArg<'_>],
implied_by_args: &[GenericArg<'_>],
implied_args: &[GenericArg<'_>],
) -> bool {
trait_predicate_args
.iter()
.enumerate()
.skip(1) // skip `Self` implicit arg
.all(|(arg_index, arg)| {
if let Some(ty) = arg.as_type()
&& let &ty::Param(ty::ParamTy{ index, .. }) = ty.kind()
// Since `trait_predicate_args` and type params in traits start with `Self=0`
// and generic argument lists `GenericTrait<i32>` don't have `Self`,
// we need to subtract 1 from the index.
&& let GenericArg::Type(ty_a) = implied_by_args[index as usize - 1]
&& let GenericArg::Type(ty_b) = implied_args[arg_index - 1]
{
hir_ty_to_ty(tcx, ty_a) == hir_ty_to_ty(tcx, ty_b)
} else {
false
}
})
}
fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
if let FnRetTy::Return(ty) = decl.output
&&let TyKind::OpaqueDef(item_id, ..) = ty.kind
&& let item = cx.tcx.hir().item(item_id)
&& let ItemKind::OpaqueTy(opaque_ty) = item.kind
// Very often there is only a single bound, e.g. `impl Deref<..>`, in which case
// we can avoid doing a bunch of stuff unnecessarily.
&& opaque_ty.bounds.len() > 1
{
// Get all the (implied) trait predicates in the bounds.
// For `impl Deref + DerefMut` this will contain [`Deref`].
// The implied `Deref` comes from `DerefMut` because `trait DerefMut: Deref {}`.
// N.B. (G)ATs are fine to disregard, because they must be the same for all of its supertraits.
// Example:
// `impl Deref<Target = i32> + DerefMut<Target = u32>` is not allowed.
// `DerefMut::Target` needs to match `Deref::Target`.
let implied_bounds: Vec<_> = opaque_ty.bounds.iter().filter_map(|bound| {
if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound
&& let [.., path] = poly_trait.trait_ref.path.segments
&& poly_trait.bound_generic_params.is_empty()
&& let Some(trait_def_id) = path.res.opt_def_id()
&& let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates
&& !predicates.is_empty() // If the trait has no supertrait, there is nothing to add.
{
Some((bound.span(), path.args.map_or([].as_slice(), |a| a.args), predicates))
} else {
None
}
}).collect();
// Lint all bounds in the `impl Trait` type that are also in the `implied_bounds` vec.
// This involves some extra logic when generic arguments are present, since
// simply comparing trait `DefId`s won't be enough. We also need to compare the generics.
for (index, bound) in opaque_ty.bounds.iter().enumerate() {
if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound
&& let [.., path] = poly_trait.trait_ref.path.segments
&& let implied_args = path.args.map_or([].as_slice(), |a| a.args)
&& let Some(def_id) = poly_trait.trait_ref.path.res.opt_def_id()
&& let Some(implied_by_span) = implied_bounds.iter().find_map(|&(span, implied_by_args, preds)| {
preds.iter().find_map(|(clause, _)| {
if let ClauseKind::Trait(tr) = clause.kind().skip_binder()
&& tr.def_id() == def_id
&& is_same_generics(cx.tcx, tr.trait_ref.args, implied_by_args, implied_args)
{
Some(span)
} else {
None
}
})
})
{
let implied_by = snippet(cx, implied_by_span, "..");
span_lint_and_then(
cx, IMPLIED_BOUNDS_IN_IMPLS,
poly_trait.span,
&format!("this bound is already specified as the supertrait of `{implied_by}`"),
|diag| {
// If we suggest removing a bound, we may also need extend the span
// to include the `+` token, so we don't end up with something like `impl + B`
let implied_span_extended = if let Some(next_bound) = opaque_ty.bounds.get(index + 1) {
poly_trait.span.to(next_bound.span().shrink_to_lo())
} else {
poly_trait.span
};
diag.span_suggestion_with_style(
implied_span_extended,
"try removing this bound",
"",
Applicability::MachineApplicable,
SuggestionStyle::ShowAlways
);
}
);
}
}
}
}
impl LateLintPass<'_> for ImpliedBoundsInImpls {
fn check_fn(
&mut self,
cx: &LateContext<'_>,
_: FnKind<'_>,
decl: &FnDecl<'_>,
_: &Body<'_>,
_: Span,
_: LocalDefId,
) {
check(cx, decl);
}
fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
if let TraitItemKind::Fn(sig, ..) = &item.kind {
check(cx, sig.decl);
}
}
fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &ImplItem<'_>) {
if let ImplItemKind::Fn(sig, ..) = &item.kind {
check(cx, sig.decl);
}
}
}

View file

@ -72,7 +72,7 @@ declare_clippy_lint! {
/// // ...
/// }
/// ```
#[clippy::version = "1.71.0"]
#[clippy::version = "1.72.0"]
pub LARGE_STACK_FRAMES,
nursery,
"checks for functions that allocate a lot of stack space"

View file

@ -152,6 +152,7 @@ mod implicit_hasher;
mod implicit_return;
mod implicit_saturating_add;
mod implicit_saturating_sub;
mod implied_bounds_in_impls;
mod inconsistent_struct_constructor;
mod incorrect_impls;
mod index_refutable_slice;
@ -285,6 +286,7 @@ mod ref_option_ref;
mod ref_patterns;
mod reference;
mod regex;
mod reserve_after_initialization;
mod return_self_not_must_use;
mod returns;
mod same_name_method;
@ -1095,6 +1097,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
});
store.register_late_pass(|_| Box::new(redundant_locals::RedundantLocals));
store.register_late_pass(|_| Box::new(ignored_unit_patterns::IgnoredUnitPatterns));
store.register_late_pass(|_| Box::<reserve_after_initialization::ReserveAfterInitialization>::default());
store.register_late_pass(|_| Box::new(implied_bounds_in_impls::ImpliedBoundsInImpls));
// add lints here, do not remove this comment, it's used in `new_lint`
}

View file

@ -12,13 +12,15 @@ use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::sym;
const ACCEPTABLE_METHODS: [&[&str]; 4] = [
const ACCEPTABLE_METHODS: [&[&str]; 5] = [
&paths::BINARYHEAP_ITER,
&paths::HASHSET_ITER,
&paths::BTREESET_ITER,
&paths::SLICE_INTO,
&paths::VEC_DEQUE_ITER,
];
const ACCEPTABLE_TYPES: [(rustc_span::Symbol, Option<RustcVersion>); 6] = [
const ACCEPTABLE_TYPES: [(rustc_span::Symbol, Option<RustcVersion>); 7] = [
(sym::BinaryHeap, Some(msrvs::BINARY_HEAP_RETAIN)),
(sym::BTreeSet, Some(msrvs::BTREE_SET_RETAIN)),
(sym::BTreeMap, Some(msrvs::BTREE_MAP_RETAIN)),
(sym::HashSet, Some(msrvs::HASH_SET_RETAIN)),

View file

@ -17,6 +17,7 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
let return_type = cx.typeck_results().expr_ty(expr);
let input_type = cx.typeck_results().expr_ty(recv);
let (input_type, ref_count) = peel_mid_ty_refs(input_type);
if !(ref_count > 0 && is_diag_trait_item(cx, method_def_id, sym::ToOwned));
if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()));
if return_type == input_type;
if let Some(clone_trait) = cx.tcx.lang_items().clone_trait();

View file

@ -1,21 +1,45 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{implements_trait, is_copy};
use rustc_ast::BindingAnnotation;
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_hir::{Body, Expr, ExprKind, HirId, HirIdSet, PatKind};
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_middle::mir::{FakeReadCause, Mutability};
use rustc_middle::ty::{self, BorrowKind};
use rustc_span::sym;
use super::ITER_OVEREAGER_CLONED;
use crate::redundant_clone::REDUNDANT_CLONE;
use crate::rustc_trait_selection::infer::TyCtxtInferExt;
#[derive(Clone, Copy)]
pub(super) enum Op<'a> {
// rm `.cloned()`
// e.g. `count`
RmCloned,
// rm `.cloned()`
// e.g. `map` `for_each`
NeedlessMove(&'a str, &'a Expr<'a>),
// later `.cloned()`
// and add `&` to the parameter of closure parameter
// e.g. `find` `filter`
FixClosure(&'a str, &'a Expr<'a>),
// later `.cloned()`
// e.g. `skip` `take`
LaterCloned,
}
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>,
cloned_call: &'tcx Expr<'_>,
cloned_recv: &'tcx Expr<'_>,
is_count: bool,
op: Op<'tcx>,
needs_into_iter: bool,
) {
let typeck = cx.typeck_results();
@ -35,10 +59,47 @@ pub(super) fn check<'tcx>(
return;
}
let (lint, msg, trailing_clone) = if is_count {
(REDUNDANT_CLONE, "unneeded cloning of iterator items", "")
} else {
(ITER_OVEREAGER_CLONED, "unnecessarily eager cloning of iterator items", ".cloned()")
if let Op::NeedlessMove(_, expr) = op {
let rustc_hir::ExprKind::Closure(closure) = expr.kind else { return } ;
let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else { return };
let mut delegate = MoveDelegate {used_move : HirIdSet::default()};
let infcx = cx.tcx.infer_ctxt().build();
ExprUseVisitor::new(
&mut delegate,
&infcx,
closure.body.hir_id.owner.def_id,
cx.param_env,
cx.typeck_results(),
)
.consume_body(body);
let mut to_be_discarded = false;
p.pat.walk(|it| {
if delegate.used_move.contains(&it.hir_id){
to_be_discarded = true;
return false;
}
match it.kind {
PatKind::Binding(BindingAnnotation(_, Mutability::Mut), _, _, _)
| PatKind::Ref(_, Mutability::Mut) => {
to_be_discarded = true;
false
}
_ => { true }
}
});
if to_be_discarded {
return;
}
}
let (lint, msg, trailing_clone) = match op {
Op::RmCloned | Op::NeedlessMove(_, _) => (REDUNDANT_CLONE, "unneeded cloning of iterator items", ""),
Op::LaterCloned | Op::FixClosure(_, _) => (ITER_OVEREAGER_CLONED, "unnecessarily eager cloning of iterator items", ".cloned()"),
};
span_lint_and_then(
@ -47,13 +108,54 @@ pub(super) fn check<'tcx>(
expr.span,
msg,
|diag| {
let method_span = expr.span.with_lo(cloned_call.span.hi());
if let Some(mut snip) = snippet_opt(cx, method_span) {
snip.push_str(trailing_clone);
let replace_span = expr.span.with_lo(cloned_recv.span.hi());
diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable);
match op {
Op::RmCloned | Op::LaterCloned => {
let method_span = expr.span.with_lo(cloned_call.span.hi());
if let Some(mut snip) = snippet_opt(cx, method_span) {
snip.push_str(trailing_clone);
let replace_span = expr.span.with_lo(cloned_recv.span.hi());
diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable);
}
}
Op::FixClosure(name, predicate_expr) => {
if let Some(predicate) = snippet_opt(cx, predicate_expr.span) {
let new_closure = if let ExprKind::Closure(_) = predicate_expr.kind {
predicate.replacen('|', "|&", 1)
} else {
format!("|&x| {predicate}(x)")
};
let snip = format!(".{name}({new_closure}).cloned()" );
let replace_span = expr.span.with_lo(cloned_recv.span.hi());
diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable);
}
}
Op::NeedlessMove(_, _) => {
let method_span = expr.span.with_lo(cloned_call.span.hi());
if let Some(snip) = snippet_opt(cx, method_span) {
let replace_span = expr.span.with_lo(cloned_recv.span.hi());
diag.span_suggestion(replace_span, "try", snip, Applicability::MaybeIncorrect);
}
}
}
}
);
}
}
struct MoveDelegate {
used_move: HirIdSet,
}
impl<'tcx> Delegate<'tcx> for MoveDelegate {
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, _: HirId) {
if let PlaceBase::Local(l) = place_with_id.place.base {
self.used_move.insert(l);
}
}
fn borrow(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: BorrowKind) {}
fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
}

View file

@ -301,7 +301,7 @@ declare_clippy_lint! {
/// let val2 = 1;
/// let val3 = 1;
/// ```
#[clippy::version = "1.69.0"]
#[clippy::version = "1.72.0"]
pub UNNECESSARY_LITERAL_UNWRAP,
complexity,
"using `unwrap()` related calls on `Result` and `Option` constructors"
@ -3328,7 +3328,7 @@ declare_clippy_lint! {
/// mem::take(v)
/// }
/// ```
#[clippy::version = "1.71.0"]
#[clippy::version = "1.72.0"]
pub DRAIN_COLLECT,
perf,
"calling `.drain(..).collect()` to move all elements into a new collection"
@ -3919,7 +3919,7 @@ impl Methods {
}
},
("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned , false),
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => {
iter_count::check(cx, expr, recv2, name2);
},
@ -3973,6 +3973,13 @@ impl Methods {
string_extend_chars::check(cx, expr, recv, arg);
extend_with_drain::check(cx, expr, recv, arg);
},
(name @ ( "filter" | "find" ) , [arg]) => {
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
// if `arg` has side-effect, the semantic will change
iter_overeager_cloned::check(cx, expr, recv, recv2,
iter_overeager_cloned::Op::FixClosure(name, arg), false);
}
}
("filter_map", [arg]) => {
unnecessary_filter_map::check(cx, expr, arg, name);
filter_map_bool_then::check(cx, expr, arg, call_span);
@ -3987,16 +3994,18 @@ impl Methods {
},
("flatten", []) => match method_call(recv) {
Some(("map", recv, [map_arg], map_span, _)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned , true),
_ => {},
},
("fold", [init, acc]) => {
manual_try_fold::check(cx, expr, init, acc, call_span, &self.msrv);
unnecessary_fold::check(cx, expr, init, acc, span);
},
("for_each", [_]) => {
if let Some(("inspect", _, [_], span2, _)) = method_call(recv) {
inspect_for_each::check(cx, expr, span2);
("for_each", [arg]) => {
match method_call(recv) {
Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2),
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, arg), false),
_ => {}
}
},
("get", [arg]) => {
@ -4021,7 +4030,8 @@ impl Methods {
},
("last", []) => {
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
iter_overeager_cloned::check(cx, expr, recv, recv2,
iter_overeager_cloned::Op::LaterCloned , false);
}
},
("lock", []) => {
@ -4030,8 +4040,10 @@ impl Methods {
(name @ ("map" | "map_err"), [m_arg]) => {
if name == "map" {
map_clone::check(cx, expr, recv, m_arg, &self.msrv);
if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) = method_call(recv) {
iter_kv_map::check(cx, map_name, expr, recv2, m_arg);
match method_call(recv) {
Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => iter_kv_map::check(cx, map_name, expr, recv2, m_arg),
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, m_arg), false),
_ => {}
}
} else {
map_err_ignore::check(cx, expr, m_arg);
@ -4058,7 +4070,7 @@ impl Methods {
("next", []) => {
if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
match (name2, args2) {
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned, false),
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, &self.msrv),
("iter", []) => iter_next_slice::check(cx, expr, recv2),
@ -4071,7 +4083,7 @@ impl Methods {
},
("nth", [n_arg]) => match method_call(recv) {
Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned , false),
Some(("iter", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
Some(("iter_mut", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
@ -4126,7 +4138,8 @@ impl Methods {
iter_skip_zero::check(cx, expr, arg);
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
iter_overeager_cloned::check(cx, expr, recv, recv2,
iter_overeager_cloned::Op::LaterCloned , false);
}
}
("sort", []) => {
@ -4152,7 +4165,8 @@ impl Methods {
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
("take", [_arg]) => {
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
iter_overeager_cloned::check(cx, expr, recv, recv2,
iter_overeager_cloned::Op::LaterCloned, false);
}
},
("take", []) => needless_option_take::check(cx, expr, recv),

View file

@ -65,11 +65,26 @@ pub(super) fn check<'tcx>(
};
let sugg = match (name, call_expr.is_some()) {
("unwrap_or", true) | ("unwrap_or_else", false) => "unwrap_or_default",
("or_insert", true) | ("or_insert_with", false) => "or_default",
("unwrap_or", true) | ("unwrap_or_else", false) => sym!(unwrap_or_default),
("or_insert", true) | ("or_insert_with", false) => sym!(or_default),
_ => return false,
};
let receiver_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs();
let has_suggested_method = receiver_ty.ty_adt_def().is_some_and(|adt_def| {
cx.tcx
.inherent_impls(adt_def.did())
.iter()
.flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg))
.any(|assoc| {
assoc.fn_has_self_parameter
&& cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1
})
});
if !has_suggested_method {
return false;
}
// needs to target Default::default in particular or be *::new and have a Default impl
// available
if (is_new(fun) && output_type_implements_default(fun))

View file

@ -27,7 +27,7 @@ declare_clippy_lint! {
/// println!("Check successful!");
/// }
/// ```
#[clippy::version = "1.71.0"]
#[clippy::version = "1.72.0"]
pub NEEDLESS_ELSE,
style,
"empty else branch"

View file

@ -130,6 +130,11 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
}
let generics_sugg = snippet(cx, generics.span, "");
let where_clause_sugg = if generics.has_where_clause_predicates {
format!("\n{}\n", snippet(cx, generics.where_clause_span, ""))
} else {
String::new()
};
let self_ty_fmt = self_ty.to_string();
let self_type_snip = snippet(cx, impl_self_ty.span, &self_ty_fmt);
span_lint_hir_and_then(
@ -145,8 +150,12 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
cx,
item.span,
"try adding this",
&create_new_without_default_suggest_msg(&self_type_snip, &generics_sugg),
Applicability::MaybeIncorrect,
&create_new_without_default_suggest_msg(
&self_type_snip,
&generics_sugg,
&where_clause_sugg
),
Applicability::MachineApplicable,
);
},
);
@ -159,10 +168,14 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
}
}
fn create_new_without_default_suggest_msg(self_type_snip: &str, generics_sugg: &str) -> String {
fn create_new_without_default_suggest_msg(
self_type_snip: &str,
generics_sugg: &str,
where_clause_sugg: &str,
) -> String {
#[rustfmt::skip]
format!(
"impl{generics_sugg} Default for {self_type_snip} {{
"impl{generics_sugg} Default for {self_type_snip}{where_clause_sugg} {{
fn default() -> Self {{
Self::new()
}}

View file

@ -278,7 +278,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// (fn_path, arg_indices) - `arg_indices` are the `arg` positions where null would cause U.B.
const INVALID_NULL_PTR_USAGE_TABLE: [(&[&str], &[usize]); 16] = [
const INVALID_NULL_PTR_USAGE_TABLE: [(&[&str], &[usize]); 13] = [
(&paths::SLICE_FROM_RAW_PARTS, &[0]),
(&paths::SLICE_FROM_RAW_PARTS_MUT, &[0]),
(&paths::PTR_COPY, &[0, 1]),
@ -291,20 +291,33 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
(&paths::PTR_SLICE_FROM_RAW_PARTS_MUT, &[0]),
(&paths::PTR_SWAP, &[0, 1]),
(&paths::PTR_SWAP_NONOVERLAPPING, &[0, 1]),
(&paths::PTR_WRITE, &[0]),
(&paths::PTR_WRITE_UNALIGNED, &[0]),
(&paths::PTR_WRITE_VOLATILE, &[0]),
(&paths::PTR_WRITE_BYTES, &[0]),
];
let invalid_null_ptr_usage_table_diag_items: [(Option<DefId>, &[usize]); 3] = [
(cx.tcx.get_diagnostic_item(sym::ptr_write), &[0]),
(cx.tcx.get_diagnostic_item(sym::ptr_write_unaligned), &[0]),
(cx.tcx.get_diagnostic_item(sym::ptr_write_volatile), &[0]),
];
if_chain! {
if let ExprKind::Call(fun, args) = expr.kind;
if let ExprKind::Path(ref qpath) = fun.kind;
if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::<Vec<_>>();
if let Some(&(_, arg_indices)) = INVALID_NULL_PTR_USAGE_TABLE
if let Some(arg_indices) = INVALID_NULL_PTR_USAGE_TABLE
.iter()
.find(|&&(fn_path, _)| fn_path == fun_def_path);
.find_map(|&(fn_path, indices)| if fn_path == fun_def_path { Some(indices) } else { None })
.or_else(|| {
invalid_null_ptr_usage_table_diag_items
.iter()
.find_map(|&(def_id, indices)| {
if def_id == Some(fun_def_id) {
Some(indices)
} else {
None
}
})
});
then {
for &arg_idx in arg_indices {
if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) {

View file

@ -31,7 +31,7 @@ declare_clippy_lint! {
/// ```rust
/// let foo = String::new();
/// ```
#[clippy::version = "1.70.0"]
#[clippy::version = "1.72.0"]
pub REDUNDANT_TYPE_ANNOTATIONS,
restriction,
"warns about needless / redundant type annotations."

View file

@ -0,0 +1,134 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
use clippy_utils::source::snippet;
use clippy_utils::{is_from_proc_macro, path_to_local_id};
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
/// Informs the user about a more concise way to create a vector with a known capacity.
///
/// ### Why is this bad?
/// The `Vec::with_capacity` constructor is less complex.
///
/// ### Example
/// ```rust
/// let mut v: Vec<usize> = vec![];
/// v.reserve(10);
/// ```
/// Use instead:
/// ```rust
/// let mut v: Vec<usize> = Vec::with_capacity(10);
/// ```
#[clippy::version = "1.73.0"]
pub RESERVE_AFTER_INITIALIZATION,
complexity,
"`reserve` called immediatly after `Vec` creation"
}
impl_lint_pass!(ReserveAfterInitialization => [RESERVE_AFTER_INITIALIZATION]);
#[derive(Default)]
pub struct ReserveAfterInitialization {
searcher: Option<VecReserveSearcher>,
}
struct VecReserveSearcher {
local_id: HirId,
err_span: Span,
init_part: String,
space_hint: String,
}
impl VecReserveSearcher {
fn display_err(&self, cx: &LateContext<'_>) {
if self.space_hint.is_empty() {
return;
}
let s = format!("{}Vec::with_capacity({});", self.init_part, self.space_hint);
span_lint_and_sugg(
cx,
RESERVE_AFTER_INITIALIZATION,
self.err_span,
"call to `reserve` immediately after creation",
"consider using `Vec::with_capacity(/* Space hint */)`",
s,
Applicability::HasPlaceholders,
);
}
}
impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
fn check_block(&mut self, _: &LateContext<'tcx>, _: &'tcx Block<'tcx>) {
self.searcher = None;
}
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
if let Some(init_expr) = local.init
&& let PatKind::Binding(BindingAnnotation::MUT, id, _, None) = local.pat.kind
&& !in_external_macro(cx.sess(), local.span)
&& let Some(init) = get_vec_init_kind(cx, init_expr)
&& !matches!(init, VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_))
{
self.searcher = Some(VecReserveSearcher {
local_id: id,
err_span: local.span,
init_part: snippet(cx, local.span.shrink_to_lo()
.to(init_expr.span.source_callsite().shrink_to_lo()), "..")
.into_owned(),
space_hint: String::new()
});
}
}
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if self.searcher.is_none()
&& let ExprKind::Assign(left, right, _) = expr.kind
&& let ExprKind::Path(QPath::Resolved(None, path)) = left.kind
&& let Res::Local(id) = path.res
&& !in_external_macro(cx.sess(), expr.span)
&& let Some(init) = get_vec_init_kind(cx, right)
&& !matches!(init, VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_))
{
self.searcher = Some(VecReserveSearcher {
local_id: id,
err_span: expr.span,
init_part: snippet(cx, left.span.shrink_to_lo()
.to(right.span.source_callsite().shrink_to_lo()), "..")
.into_owned(), // see `assign_expression` test
space_hint: String::new()
});
}
}
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
if let Some(searcher) = self.searcher.take() {
if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
&& let ExprKind::MethodCall(name, self_arg, [space_hint], _) = expr.kind
&& path_to_local_id(self_arg, searcher.local_id)
&& name.ident.as_str() == "reserve"
&& !is_from_proc_macro(cx, expr)
{
self.searcher = Some(VecReserveSearcher {
err_span: searcher.err_span.to(stmt.span),
space_hint: snippet(cx, space_hint.span, "..").into_owned(),
.. searcher
});
} else {
searcher.display_err(cx);
}
}
}
fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx Block<'tcx>) {
if let Some(searcher) = self.searcher.take() {
searcher.display_err(cx);
}
}
}

View file

@ -189,8 +189,8 @@ fn all_bindings_are_for_conv<'tcx>(
tys.len() == elements.len() && tys.iter().chain(final_tys.iter().copied()).all_equal()
},
(ToType::Tuple, ty::Array(ty, len)) => {
len.eval_target_usize(cx.tcx, cx.param_env) as usize == elements.len()
&& final_tys.iter().chain(once(ty)).all_equal()
let Some(len) = len.try_eval_target_usize(cx.tcx, cx.param_env) else { return false };
len as usize == elements.len() && final_tys.iter().chain(once(ty)).all_equal()
},
_ => false,
}

View file

@ -1,6 +1,6 @@
[package]
name = "clippy_utils"
version = "0.1.73"
version = "0.1.74"
edition = "2021"
publish = false

View file

@ -5,12 +5,12 @@ use crate::tokenize_with_text;
use rustc_ast::ast::InlineAsmTemplatePiece;
use rustc_data_structures::fx::FxHasher;
use rustc_hir::def::Res;
use rustc_hir::MatchSource::TryDesugar;
use rustc_hir::{
ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
GenericArgs, Guard, HirId, HirIdMap, InlineAsmOperand, Let, Lifetime, LifetimeName, Pat, PatField, PatKind, Path,
PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
};
use rustc_hir::MatchSource::TryDesugar;
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::LateContext;
use rustc_middle::ty::TypeckResults;

View file

@ -20,7 +20,7 @@ macro_rules! msrv_aliases {
// names may refer to stabilized feature flags or library items
msrv_aliases! {
1,71,0 { TUPLE_ARRAY_CONVERSIONS }
1,70,0 { OPTION_IS_SOME_AND }
1,70,0 { OPTION_IS_SOME_AND, BINARY_HEAP_RETAIN }
1,68,0 { PATH_MAIN_SEPARATOR_STR }
1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }

View file

@ -15,6 +15,7 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [
];
#[cfg(feature = "internal")]
pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"];
pub const BINARYHEAP_ITER: [&str; 5] = ["alloc", "collections", "binary_heap", "BinaryHeap", "iter"];
pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"];
pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"];
pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"];
@ -86,10 +87,7 @@ pub const PTR_REPLACE: [&str; 3] = ["core", "ptr", "replace"];
pub const PTR_SWAP: [&str; 3] = ["core", "ptr", "swap"];
pub const PTR_UNALIGNED_VOLATILE_LOAD: [&str; 3] = ["core", "intrinsics", "unaligned_volatile_load"];
pub const PTR_UNALIGNED_VOLATILE_STORE: [&str; 3] = ["core", "intrinsics", "unaligned_volatile_store"];
pub const PTR_WRITE: [&str; 3] = ["core", "ptr", "write"];
pub const PTR_WRITE_BYTES: [&str; 3] = ["core", "intrinsics", "write_bytes"];
pub const PTR_WRITE_UNALIGNED: [&str; 3] = ["core", "ptr", "write_unaligned"];
pub const PTR_WRITE_VOLATILE: [&str; 3] = ["core", "ptr", "write_volatile"];
pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"];

View file

@ -1,6 +1,6 @@
[package]
name = "declare_clippy_lint"
version = "0.1.73"
version = "0.1.74"
edition = "2021"
publish = false

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2023-08-10"
channel = "nightly-2023-08-24"
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]

View file

@ -1,16 +1,13 @@
#![feature(test)] // compiletest_rs requires this attribute
#![feature(lazy_cell)]
#![feature(is_sorted)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
#![allow(unused_extern_crates)]
use compiletest::{status_emitter, CommandBuilder, OutputConflictHandling};
use ui_test as compiletest;
use ui_test::Mode as TestMode;
use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, Mode, OutputConflictHandling, RustfixMode};
use std::collections::BTreeMap;
use std::env::{self, remove_var, set_var, var_os};
use std::env::{self, set_var, var_os};
use std::ffi::{OsStr, OsString};
use std::fs;
use std::path::{Path, PathBuf};
@ -30,6 +27,8 @@ extern crate quote;
extern crate syn;
extern crate tokio;
mod test_utils;
/// All crates used in UI tests are listed here
static TEST_DEPENDENCIES: &[&str] = &[
"clippy_lints",
@ -105,33 +104,44 @@ static EXTERN_FLAGS: LazyLock<Vec<String>> = LazyLock::new(|| {
.collect()
});
mod test_utils;
// whether to run internal tests or not
const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal");
fn base_config(test_dir: &str) -> compiletest::Config {
let mut config = compiletest::Config {
mode: TestMode::Yolo,
stderr_filters: vec![],
fn canonicalize(path: impl AsRef<Path>) -> PathBuf {
let path = path.as_ref();
fs::create_dir_all(path).unwrap();
fs::canonicalize(path).unwrap_or_else(|err| panic!("{} cannot be canonicalized: {err}", path.display()))
}
fn base_config(test_dir: &str) -> (Config, Args) {
let bless = var_os("RUSTC_BLESS").is_some_and(|v| v != "0") || env::args().any(|arg| arg == "--bless");
let args = Args {
filters: env::var("TESTNAME")
.map(|filters| filters.split(',').map(str::to_string).collect())
.unwrap_or_default(),
quiet: false,
check: !bless,
threads: match std::env::var_os("RUST_TEST_THREADS") {
Some(n) => n.to_str().unwrap().parse().unwrap(),
None => std::thread::available_parallelism().unwrap(),
},
skip: Vec::new(),
};
let mut config = Config {
mode: Mode::Yolo { rustfix: RustfixMode::Everything },
stderr_filters: vec![(Match::PathBackslash, b"/")],
stdout_filters: vec![],
output_conflict_handling: if var_os("RUSTC_BLESS").is_some_and(|v| v != "0")
|| env::args().any(|arg| arg == "--bless")
{
output_conflict_handling: if bless {
OutputConflictHandling::Bless
} else {
OutputConflictHandling::Error("cargo uibless".into())
},
target: None,
out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap_or("target".into())).join("ui_test"),
..compiletest::Config::rustc(Path::new("tests").join(test_dir))
out_dir: canonicalize(var_os("CARGO_TARGET_DIR").unwrap_or_else(|| "target".into())).join("ui_test"),
..Config::rustc(Path::new("tests").join(test_dir))
};
if let Some(_path) = option_env!("RUSTC_LIB_PATH") {
//let path = PathBuf::from(path);
//config.run_lib_path = path.clone();
//config.compile_lib_path = path;
}
let current_exe_path = env::current_exe().unwrap();
let deps_path = current_exe_path.parent().unwrap();
let profile_path = deps_path.parent().unwrap();
@ -155,52 +165,35 @@ fn base_config(test_dir: &str) -> compiletest::Config {
config.program.args.push(dep.into());
}
// Normalize away slashes in windows paths.
config.stderr_filter(r"\\", "/");
//config.build_base = profile_path.join("test").join(test_dir);
config.program.program = profile_path.join(if cfg!(windows) {
"clippy-driver.exe"
} else {
"clippy-driver"
});
config
}
fn test_filter() -> Box<dyn Sync + Fn(&Path) -> bool> {
if let Ok(filters) = env::var("TESTNAME") {
let filters: Vec<_> = filters.split(',').map(ToString::to_string).collect();
Box::new(move |path| filters.iter().any(|f| path.to_string_lossy().contains(f)))
} else {
Box::new(|_| true)
}
(config, args)
}
fn run_ui() {
let config = base_config("ui");
//config.rustfix_coverage = true;
// use tests/clippy.toml
let _g = VarGuard::set("CARGO_MANIFEST_DIR", fs::canonicalize("tests").unwrap());
let _threads = VarGuard::set(
"RUST_TEST_THREADS",
// if RUST_TEST_THREADS is set, adhere to it, otherwise override it
env::var("RUST_TEST_THREADS").unwrap_or_else(|_| {
std::thread::available_parallelism()
.map_or(1, std::num::NonZeroUsize::get)
.to_string()
}),
);
let (mut config, args) = base_config("ui");
config
.program
.envs
.push(("CLIPPY_CONF_DIR".into(), Some(canonicalize("tests").into())));
let test_filter = test_filter();
let quiet = args.quiet;
compiletest::run_tests_generic(
config,
move |path| compiletest::default_file_filter(path) && test_filter(path),
compiletest::default_per_file_config,
status_emitter::Text,
ui_test::run_tests_generic(
vec![config],
args,
ui_test::default_file_filter,
ui_test::default_per_file_config,
if quiet {
status_emitter::Text::quiet()
} else {
status_emitter::Text::verbose()
},
)
.unwrap();
check_rustfix_coverage();
}
fn run_internal_tests() {
@ -208,51 +201,61 @@ fn run_internal_tests() {
if !RUN_INTERNAL_TESTS {
return;
}
let mut config = base_config("ui-internal");
let (mut config, args) = base_config("ui-internal");
if let OutputConflictHandling::Error(err) = &mut config.output_conflict_handling {
*err = "cargo uitest --features internal -- -- --bless".into();
}
let test_filter = test_filter();
let quiet = args.quiet;
compiletest::run_tests_generic(
config,
move |path| compiletest::default_file_filter(path) && test_filter(path),
compiletest::default_per_file_config,
status_emitter::Text,
ui_test::run_tests_generic(
vec![config],
args,
ui_test::default_file_filter,
ui_test::default_per_file_config,
if quiet {
status_emitter::Text::quiet()
} else {
status_emitter::Text::verbose()
},
)
.unwrap();
}
fn run_ui_toml() {
let mut config = base_config("ui-toml");
let (mut config, args) = base_config("ui-toml");
config.stderr_filter(
&regex::escape(
&fs::canonicalize("tests")
.unwrap()
.parent()
.unwrap()
.display()
.to_string()
.replace('\\', "/"),
config.stderr_filters = vec![
(
Match::Exact(
canonicalize("tests")
.parent()
.unwrap()
.to_string_lossy()
.as_bytes()
.to_vec(),
),
b"$DIR",
),
"$$DIR",
);
(Match::Exact(b"\\".to_vec()), b"/"),
];
let test_filter = test_filter();
let quiet = args.quiet;
ui_test::run_tests_generic(
config,
|path| compiletest::default_file_filter(path) && test_filter(path),
|config, path| {
let mut config = config.clone();
vec![config],
args,
ui_test::default_file_filter,
|config, path, _file_contents| {
config
.program
.envs
.push(("CLIPPY_CONF_DIR".into(), Some(path.parent().unwrap().into())));
Some(config)
},
status_emitter::Text,
if quiet {
status_emitter::Text::quiet()
} else {
status_emitter::Text::verbose()
},
)
.unwrap();
}
@ -262,7 +265,7 @@ fn run_ui_cargo() {
return;
}
let mut config = base_config("ui-cargo");
let (mut config, args) = base_config("ui-cargo");
config.program.input_file_flag = CommandBuilder::cargo().input_file_flag;
config.program.out_dir_flag = CommandBuilder::cargo().out_dir_flag;
config.program.args = vec!["clippy".into(), "--color".into(), "never".into(), "--quiet".into()];
@ -280,30 +283,41 @@ fn run_ui_cargo() {
});
config.edition = None;
config.stderr_filter(
&regex::escape(
&fs::canonicalize("tests")
.unwrap()
.parent()
.unwrap()
.display()
.to_string()
.replace('\\', "/"),
config.stderr_filters = vec![
(
Match::Exact(
canonicalize("tests")
.parent()
.unwrap()
.to_string_lossy()
.as_bytes()
.to_vec(),
),
b"$DIR",
),
"$$DIR",
);
(Match::Exact(b"\\".to_vec()), b"/"),
];
let test_filter = test_filter();
let quiet = args.quiet;
ui_test::run_tests_generic(
config,
|path| test_filter(path) && path.ends_with("Cargo.toml"),
|config, path| {
let mut config = config.clone();
config.out_dir = PathBuf::from("target/ui_test_cargo/").join(path.parent().unwrap());
Some(config)
vec![config],
args,
|path, args, _config| path.ends_with("Cargo.toml") && ui_test::default_filter_by_arg(path, args),
|config, path, _file_contents| {
config.out_dir = canonicalize(
std::env::current_dir()
.unwrap()
.join("target")
.join("ui_test_cargo/")
.join(path.parent().unwrap()),
);
},
if quiet {
status_emitter::Text::quiet()
} else {
status_emitter::Text::verbose()
},
status_emitter::Text,
)
.unwrap();
}
@ -328,7 +342,6 @@ fn main() {
"cargo" => run_ui_cargo as fn(),
"toml" => run_ui_toml as fn(),
"internal" => run_internal_tests as fn(),
"rustfix-coverage-known-exceptions-accuracy" => rustfix_coverage_known_exceptions_accuracy as fn(),
"ui-cargo-toml-metadata" => ui_cargo_toml_metadata as fn(),
_ => panic!("unknown speedtest: {speedtest} || accepted speedtests are: [ui, cargo, toml, internal]"),
@ -349,95 +362,20 @@ fn main() {
f();
sum += start.elapsed().as_millis();
}
println!("average {} time: {} millis.", speedtest.to_uppercase(), sum / 1000);
println!(
"average {} time: {} millis.",
speedtest.to_uppercase(),
sum / u128::from(iterations)
);
} else {
run_ui();
run_ui_toml();
run_ui_cargo();
run_internal_tests();
rustfix_coverage_known_exceptions_accuracy();
ui_cargo_toml_metadata();
}
}
const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[
"assign_ops2.rs",
"borrow_deref_ref_unfixable.rs",
"cast_size_32bit.rs",
"char_lit_as_u8.rs",
"cmp_owned/without_suggestion.rs",
"dbg_macro.rs",
"deref_addrof_double_trigger.rs",
"doc/unbalanced_ticks.rs",
"eprint_with_newline.rs",
"explicit_counter_loop.rs",
"iter_skip_next_unfixable.rs",
"let_and_return.rs",
"literals.rs",
"map_flatten.rs",
"map_unwrap_or.rs",
"match_bool.rs",
"mem_replace_macro.rs",
"needless_arbitrary_self_type_unfixable.rs",
"needless_borrow_pat.rs",
"needless_for_each_unfixable.rs",
"nonminimal_bool.rs",
"print_literal.rs",
"redundant_static_lifetimes_multiple.rs",
"ref_binding_to_reference.rs",
"repl_uninit.rs",
"result_map_unit_fn_unfixable.rs",
"search_is_some.rs",
"single_component_path_imports_nested_first.rs",
"string_add.rs",
"suspicious_to_owned.rs",
"toplevel_ref_arg_non_rustfix.rs",
"unit_arg.rs",
"unnecessary_clone.rs",
"unnecessary_lazy_eval_unfixable.rs",
"write_literal.rs",
"write_literal_2.rs",
];
fn check_rustfix_coverage() {
let missing_coverage_path = Path::new("debug/test/ui/rustfix_missing_coverage.txt");
let missing_coverage_path = if let Ok(target_dir) = std::env::var("CARGO_TARGET_DIR") {
PathBuf::from(target_dir).join(missing_coverage_path)
} else {
missing_coverage_path.to_path_buf()
};
if let Ok(missing_coverage_contents) = std::fs::read_to_string(missing_coverage_path) {
assert!(RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS.iter().is_sorted_by_key(Path::new));
for rs_file in missing_coverage_contents.lines() {
let rs_path = Path::new(rs_file);
if rs_path.starts_with("tests/ui/crashes") {
continue;
}
assert!(rs_path.starts_with("tests/ui/"), "{rs_file:?}");
let filename = rs_path.strip_prefix("tests/ui/").unwrap();
assert!(
RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS
.binary_search_by_key(&filename, Path::new)
.is_ok(),
"`{rs_file}` runs `MachineApplicable` diagnostics but is missing a `run-rustfix` annotation. \
Please either add `//@run-rustfix` at the top of the file or add the file to \
`RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS` in `tests/compile-test.rs`.",
);
}
}
}
fn rustfix_coverage_known_exceptions_accuracy() {
for filename in RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS {
let rs_path = Path::new("tests/ui").join(filename);
assert!(rs_path.exists(), "`{}` does not exist", rs_path.display());
let fixed_path = rs_path.with_extension("fixed");
assert!(!fixed_path.exists(), "`{}` exists", fixed_path.display());
}
}
fn ui_cargo_toml_metadata() {
let ui_cargo_path = Path::new("tests/ui-cargo");
let cargo_common_metadata_path = ui_cargo_path.join("cargo_common_metadata");
@ -473,27 +411,3 @@ fn ui_cargo_toml_metadata() {
);
}
}
/// Restores an env var on drop
#[must_use]
struct VarGuard {
key: &'static str,
value: Option<OsString>,
}
impl VarGuard {
fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
let value = var_os(key);
set_var(key, val);
Self { key, value }
}
}
impl Drop for VarGuard {
fn drop(&mut self) {
match self.value.as_deref() {
None => remove_var(self.key),
Some(value) => set_var(self.key, value),
}
}
}

View file

@ -16,7 +16,7 @@ fn old_test_headers() {
continue;
}
let file = fs::read_to_string(entry.path()).unwrap();
let file = fs::read_to_string(entry.path()).unwrap_or_else(|err| panic!("{}: {err}", entry.path().display()));
if let Some(header) = old_headers.find(&file) {
println!("Found header `{}` in {}", header.as_str(), entry.path().display());

View file

@ -1,4 +1,3 @@
//@run-rustfix
#![deny(clippy::internal)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]

View file

@ -1,4 +1,3 @@
//@run-rustfix
#![deny(clippy::internal)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]

View file

@ -1,5 +1,5 @@
error: this call is collapsible
--> $DIR/collapsible_span_lint_calls.rs:36:9
--> $DIR/collapsible_span_lint_calls.rs:35:9
|
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.span_suggestion(expr.span, help_msg, sugg.to_string(), Applicability::MachineApplicable);
@ -7,14 +7,14 @@ LL | | });
| |__________^ help: collapse into: `span_lint_and_sugg(cx, TEST_LINT, expr.span, lint_msg, help_msg, sugg.to_string(), Applicability::MachineApplicable)`
|
note: the lint level is defined here
--> $DIR/collapsible_span_lint_calls.rs:2:9
--> $DIR/collapsible_span_lint_calls.rs:1:9
|
LL | #![deny(clippy::internal)]
| ^^^^^^^^^^^^^^^^
= note: `#[deny(clippy::collapsible_span_lint_calls)]` implied by `#[deny(clippy::internal)]`
error: this call is collapsible
--> $DIR/collapsible_span_lint_calls.rs:39:9
--> $DIR/collapsible_span_lint_calls.rs:38:9
|
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.span_help(expr.span, help_msg);
@ -22,7 +22,7 @@ LL | | });
| |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg)`
error: this call is collapsible
--> $DIR/collapsible_span_lint_calls.rs:42:9
--> $DIR/collapsible_span_lint_calls.rs:41:9
|
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.help(help_msg);
@ -30,7 +30,7 @@ LL | | });
| |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg)`
error: this call is collapsible
--> $DIR/collapsible_span_lint_calls.rs:45:9
--> $DIR/collapsible_span_lint_calls.rs:44:9
|
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.span_note(expr.span, note_msg);
@ -38,7 +38,7 @@ LL | | });
| |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg)`
error: this call is collapsible
--> $DIR/collapsible_span_lint_calls.rs:48:9
--> $DIR/collapsible_span_lint_calls.rs:47:9
|
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.note(note_msg);

View file

@ -1,4 +1,3 @@
//@run-rustfix
#![deny(clippy::internal)]
#![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)]
#![feature(rustc_private)]

View file

@ -1,4 +1,3 @@
//@run-rustfix
#![deny(clippy::internal)]
#![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)]
#![feature(rustc_private)]

View file

@ -1,30 +1,30 @@
error: interning a defined symbol
--> $DIR/interning_defined_symbol.rs:18:13
--> $DIR/interning_defined_symbol.rs:17:13
|
LL | let _ = Symbol::intern("f32");
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::f32`
|
note: the lint level is defined here
--> $DIR/interning_defined_symbol.rs:2:9
--> $DIR/interning_defined_symbol.rs:1:9
|
LL | #![deny(clippy::internal)]
| ^^^^^^^^^^^^^^^^
= note: `#[deny(clippy::interning_defined_symbol)]` implied by `#[deny(clippy::internal)]`
error: interning a defined symbol
--> $DIR/interning_defined_symbol.rs:21:13
--> $DIR/interning_defined_symbol.rs:20:13
|
LL | let _ = sym!(f32);
| ^^^^^^^^^ help: try: `rustc_span::sym::f32`
error: interning a defined symbol
--> $DIR/interning_defined_symbol.rs:24:13
--> $DIR/interning_defined_symbol.rs:23:13
|
LL | let _ = Symbol::intern("proc-macro");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::proc_dash_macro`
error: interning a defined symbol
--> $DIR/interning_defined_symbol.rs:27:13
--> $DIR/interning_defined_symbol.rs:26:13
|
LL | let _ = Symbol::intern("self");
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::symbol::kw::SelfLower`

View file

@ -1,5 +1,3 @@
//@run-rustfix
#![deny(clippy::internal)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]

View file

@ -1,5 +1,3 @@
//@run-rustfix
#![deny(clippy::internal)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]

View file

@ -1,11 +1,11 @@
error: `extract_msrv_attr!` macro missing from `LateLintPass` implementation
--> $DIR/invalid_msrv_attr_impl.rs:30:1
--> $DIR/invalid_msrv_attr_impl.rs:28:1
|
LL | impl LateLintPass<'_> for Pass {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/invalid_msrv_attr_impl.rs:3:9
--> $DIR/invalid_msrv_attr_impl.rs:1:9
|
LL | #![deny(clippy::internal)]
| ^^^^^^^^^^^^^^^^
@ -17,7 +17,7 @@ LL + extract_msrv_attr!(LateContext);
|
error: `extract_msrv_attr!` macro missing from `EarlyLintPass` implementation
--> $DIR/invalid_msrv_attr_impl.rs:34:1
--> $DIR/invalid_msrv_attr_impl.rs:32:1
|
LL | impl EarlyLintPass for Pass {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,5 +1,3 @@
//@run-rustfix
#![deny(clippy::internal)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]

View file

@ -1,5 +1,3 @@
//@run-rustfix
#![deny(clippy::internal)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]

View file

@ -1,11 +1,11 @@
error: usage of `outer_expn().expn_data()`
--> $DIR/outer_expn_data.rs:25:34
--> $DIR/outer_expn_data.rs:23:34
|
LL | let _ = expr.span.ctxt().outer_expn().expn_data();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `outer_expn_data()`
|
note: the lint level is defined here
--> $DIR/outer_expn_data.rs:3:9
--> $DIR/outer_expn_data.rs:1:9
|
LL | #![deny(clippy::internal)]
| ^^^^^^^^^^^^^^^^

View file

@ -1,4 +1,3 @@
//@run-rustfix
//@aux-build:paths.rs
#![deny(clippy::internal)]
#![feature(rustc_private)]

View file

@ -1,4 +1,3 @@
//@run-rustfix
//@aux-build:paths.rs
#![deny(clippy::internal)]
#![feature(rustc_private)]

View file

@ -1,72 +1,72 @@
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:37:13
--> $DIR/unnecessary_def_path.rs:36:13
|
LL | let _ = match_type(cx, ty, &OPTION);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)`
|
note: the lint level is defined here
--> $DIR/unnecessary_def_path.rs:3:9
--> $DIR/unnecessary_def_path.rs:2:9
|
LL | #![deny(clippy::internal)]
| ^^^^^^^^^^^^^^^^
= note: `#[deny(clippy::unnecessary_def_path)]` implied by `#[deny(clippy::internal)]`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:38:13
--> $DIR/unnecessary_def_path.rs:37:13
|
LL | let _ = match_type(cx, ty, RESULT);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:39:13
--> $DIR/unnecessary_def_path.rs:38:13
|
LL | let _ = match_type(cx, ty, &["core", "result", "Result"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:43:13
--> $DIR/unnecessary_def_path.rs:42:13
|
LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Rc)`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:45:13
--> $DIR/unnecessary_def_path.rs:44:13
|
LL | let _ = match_type(cx, ty, &paths::OPTION);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:46:13
--> $DIR/unnecessary_def_path.rs:45:13
|
LL | let _ = match_type(cx, ty, paths::RESULT);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
error: use of a def path to a `LangItem`
--> $DIR/unnecessary_def_path.rs:48:13
--> $DIR/unnecessary_def_path.rs:47:13
|
LL | let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_lang_item(cx, ty, LangItem::OwnedBox)`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:49:13
--> $DIR/unnecessary_def_path.rs:48:13
|
LL | let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit)`
error: use of a def path to a `LangItem`
--> $DIR/unnecessary_def_path.rs:51:13
--> $DIR/unnecessary_def_path.rs:50:13
|
LL | let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OwnedBox) == Some(did)`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:52:13
--> $DIR/unnecessary_def_path.rs:51:13
|
LL | let _ = match_def_path(cx, did, &["core", "option", "Option"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.is_diagnostic_item(sym::Option, did)`
error: use of a def path to a `LangItem`
--> $DIR/unnecessary_def_path.rs:53:13
--> $DIR/unnecessary_def_path.rs:52:13
|
LL | let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OptionSome) == Some(did)`
@ -74,25 +74,25 @@ LL | let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]);
= help: if this `DefId` came from a constructor expression or pattern then the parent `DefId` should be used instead
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:55:13
--> $DIR/unnecessary_def_path.rs:54:13
|
LL | let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_trait_method(cx, expr, sym::AsRef)`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:57:13
--> $DIR/unnecessary_def_path.rs:56:13
|
LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_path_diagnostic_item(cx, expr, sym::Option)`
error: use of a def path to a `LangItem`
--> $DIR/unnecessary_def_path.rs:58:13
--> $DIR/unnecessary_def_path.rs:57:13
|
LL | let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().get(LangItem::IteratorNext) == Some(id))`
error: use of a def path to a `LangItem`
--> $DIR/unnecessary_def_path.rs:59:13
--> $DIR/unnecessary_def_path.rs:58:13
|
LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome)`

View file

@ -1,4 +1,3 @@
//@run-rustfix
#![feature(rustc_private)]
#![deny(clippy::internal)]
#![allow(

View file

@ -1,4 +1,3 @@
//@run-rustfix
#![feature(rustc_private)]
#![deny(clippy::internal)]
#![allow(

View file

@ -1,36 +1,36 @@
error: unnecessary `Symbol` to string conversion
--> $DIR/unnecessary_symbol_str.rs:16:5
--> $DIR/unnecessary_symbol_str.rs:15:5
|
LL | Symbol::intern("foo").as_str() == "clippy";
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::sym::clippy`
|
note: the lint level is defined here
--> $DIR/unnecessary_symbol_str.rs:3:9
--> $DIR/unnecessary_symbol_str.rs:2:9
|
LL | #![deny(clippy::internal)]
| ^^^^^^^^^^^^^^^^
= note: `#[deny(clippy::unnecessary_symbol_str)]` implied by `#[deny(clippy::internal)]`
error: unnecessary `Symbol` to string conversion
--> $DIR/unnecessary_symbol_str.rs:17:5
--> $DIR/unnecessary_symbol_str.rs:16:5
|
LL | Symbol::intern("foo").to_string() == "self";
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::symbol::kw::SelfLower`
error: unnecessary `Symbol` to string conversion
--> $DIR/unnecessary_symbol_str.rs:18:5
--> $DIR/unnecessary_symbol_str.rs:17:5
|
LL | Symbol::intern("foo").to_ident_string() != "Self";
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") != rustc_span::symbol::kw::SelfUpper`
error: unnecessary `Symbol` to string conversion
--> $DIR/unnecessary_symbol_str.rs:19:5
--> $DIR/unnecessary_symbol_str.rs:18:5
|
LL | &*Ident::empty().as_str() == "clippy";
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::clippy`
error: unnecessary `Symbol` to string conversion
--> $DIR/unnecessary_symbol_str.rs:20:5
--> $DIR/unnecessary_symbol_str.rs:19:5
|
LL | "clippy" == Ident::empty().to_string();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name`

View file

@ -1,4 +1,4 @@
//@aux-build:../../ui/auxiliary/proc_macros.rs:proc-macro
//@aux-build:../../ui/auxiliary/proc_macros.rs
//@aux-build:helper.rs
//@revisions: allow_crates disallow_crates
//@[allow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/allow_crates

View file

@ -1,4 +1,3 @@
//@run-rustfix
#![warn(clippy::uninlined_format_args)]
#![allow(clippy::unnecessary_literal_unwrap)]

View file

@ -1,4 +1,3 @@
//@run-rustfix
#![warn(clippy::uninlined_format_args)]
#![allow(clippy::unnecessary_literal_unwrap)]

View file

@ -1,5 +1,5 @@
error: variables can be used directly in the `format!` string
--> $DIR/uninlined_format_args.rs:10:5
--> $DIR/uninlined_format_args.rs:9:5
|
LL | println!("val='{}'", local_i32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -12,7 +12,7 @@ LL + println!("val='{local_i32}'");
|
error: variables can be used directly in the `format!` string
--> $DIR/uninlined_format_args.rs:11:5
--> $DIR/uninlined_format_args.rs:10:5
|
LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -24,7 +24,7 @@ LL + println!("Hello {} is {local_f64:.local_i32$}", "x");
|
error: literal with an empty format string
--> $DIR/uninlined_format_args.rs:11:35
--> $DIR/uninlined_format_args.rs:10:35
|
LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64);
| ^^^
@ -37,7 +37,7 @@ LL + println!("Hello x is {:.*}", local_i32, local_f64);
|
error: variables can be used directly in the `format!` string
--> $DIR/uninlined_format_args.rs:12:5
--> $DIR/uninlined_format_args.rs:11:5
|
LL | println!("Hello {} is {:.*}", local_i32, 5, local_f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -49,7 +49,7 @@ LL + println!("Hello {local_i32} is {local_f64:.*}", 5);
|
error: variables can be used directly in the `format!` string
--> $DIR/uninlined_format_args.rs:13:5
--> $DIR/uninlined_format_args.rs:12:5
|
LL | println!("Hello {} is {2:.*}", local_i32, 5, local_f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -61,7 +61,7 @@ LL + println!("Hello {local_i32} is {local_f64:.*}", 5);
|
error: variables can be used directly in the `format!` string
--> $DIR/uninlined_format_args.rs:14:5
--> $DIR/uninlined_format_args.rs:13:5
|
LL | println!("{}, {}", local_i32, local_opt.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,6 +1,6 @@
#![allow(unused)]
#![warn(clippy::large_const_arrays, clippy::large_stack_arrays)]
//@no-rustfix
const ABOVE: [u8; 11] = [0; 11];
const BELOW: [u8; 10] = [0; 10];

View file

@ -1,6 +1,6 @@
//@compile-flags: --test
#![warn(clippy::dbg_macro)]
//@no-rustfix
fn foo(n: u32) -> u32 {
if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n }
}

View file

@ -0,0 +1,12 @@
#![warn(clippy::doc_markdown)]
/// This is a special interface for ClipPy which doesn't require backticks
fn allowed_name() {}
/// OAuth and LaTeX are inside Clippy's default list.
fn default_name() {}
/// `TestItemThingyOfCoolness` might sound cool but is not on the list and should be linted.
fn unknown_name() {}
fn main() {}

View file

@ -0,0 +1,12 @@
#![warn(clippy::doc_markdown)]
/// This is a special interface for ClipPy which doesn't require backticks
fn allowed_name() {}
/// `OAuth` and `LaTeX` are inside Clippy's default list.
fn default_name() {}
/// `TestItemThingyOfCoolness` might sound cool but is not on the list and should be linted.
fn unknown_name() {}
fn main() {}

View file

@ -1,4 +1,4 @@
//@aux-build:proc_macros.rs:proc-macro
//@aux-build:proc_macros.rs
#![rustfmt::skip]
#![feature(custom_inner_attributes)]
#![allow(unused)]

View file

@ -0,0 +1,27 @@
#![warn(clippy::large_futures)]
fn main() {}
pub async fn should_warn() {
let x = [0u8; 1024];
async {}.await;
dbg!(x);
}
pub async fn should_not_warn() {
let x = [0u8; 1020];
async {}.await;
dbg!(x);
}
pub async fn bar() {
Box::pin(should_warn()).await;
async {
let x = [0u8; 1024];
dbg!(x);
}
.await;
should_not_warn().await;
}

View file

@ -0,0 +1,23 @@
#![allow(clippy::excessive_precision)]
#![warn(clippy::unreadable_literal)]
fn allow_inconsistent_digit_grouping() {
#![allow(clippy::inconsistent_digit_grouping)]
let _pass1 = 100_200_300.123456789;
}
fn main() {
allow_inconsistent_digit_grouping();
let _pass1 = 100_200_300.100_200_300;
let _pass2 = 1.123456789;
let _pass3 = 1.0;
let _pass4 = 10000.00001;
let _pass5 = 1.123456789e1;
// due to clippy::inconsistent-digit-grouping
let _fail1 = 100_200_300.123_456_789;
// fail due to the integer part
let _fail2 = 100_200_300.300_200_100;
}

View file

@ -0,0 +1,24 @@
#![deny(clippy::index_refutable_slice)]
fn below_limit() {
let slice: Option<&[u32]> = Some(&[1, 2, 3]);
if let Some([_, _, _, _, _, _, _, slice_7, ..]) = slice {
//~^ ERROR: binding can be a slice pattern
// This would usually not be linted but is included now due to the
// index limit in the config file
println!("{}", slice_7);
}
}
fn above_limit() {
let slice: Option<&[u32]> = Some(&[1, 2, 3]);
if let Some(slice) = slice {
// This will not be linted as 8 is above the limit
println!("{}", slice[8]);
}
}
fn main() {
below_limit();
above_limit();
}

View file

@ -0,0 +1,98 @@
#![allow(clippy::redundant_clone, clippy::unnecessary_operation)]
#![warn(clippy::manual_non_exhaustive, clippy::borrow_as_ptr, clippy::manual_bits)]
use std::mem::{size_of, size_of_val};
use std::ops::Deref;
mod enums {
enum E {
A,
B,
#[doc(hidden)]
_C,
}
// user forgot to remove the marker
#[non_exhaustive]
enum Ep {
A,
B,
#[doc(hidden)]
_C,
}
}
fn option_as_ref_deref() {
let mut opt = Some(String::from("123"));
let _ = opt.as_ref().map(String::as_str);
let _ = opt.as_ref().map(|x| x.as_str());
let _ = opt.as_mut().map(String::as_mut_str);
let _ = opt.as_mut().map(|x| x.as_mut_str());
}
fn match_like_matches() {
let _y = match Some(5) {
Some(0) => true,
_ => false,
};
}
fn match_same_arms() {
match (1, 2, 3) {
(1, .., 3) => 42,
(.., 3) => 42,
_ => 0,
};
}
fn match_same_arms2() {
let _ = match Some(42) {
Some(_) => 24,
None => 24,
};
}
fn manual_strip_msrv() {
let s = "hello, world!";
if s.starts_with("hello, ") {
assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
}
}
fn check_index_refutable_slice() {
// This shouldn't trigger `clippy::index_refutable_slice` as the suggestion
// would only be valid from 1.42.0 onward
let slice: Option<&[u32]> = Some(&[1]);
if let Some(slice) = slice {
println!("{}", slice[0]);
}
}
fn map_clone_suggest_copied() {
// This should still trigger the lint but suggest `cloned()` instead of `copied()`
let _: Option<u64> = Some(&16).cloned();
}
fn borrow_as_ptr() {
let val = 1;
let _p = &val as *const i32;
let mut val_mut = 1;
let _p_mut = &mut val_mut as *mut i32;
}
fn manual_bits() {
size_of::<i8>() * 8;
size_of_val(&0u32) * 8;
}
fn main() {
option_as_ref_deref();
match_like_matches();
match_same_arms();
match_same_arms2();
manual_strip_msrv();
check_index_refutable_slice();
borrow_as_ptr();
}

View file

@ -0,0 +1,16 @@
#![warn(clippy::missing_enforced_import_renames)]
use std::alloc as colla;
use std::option::Option as Maybe;
use std::process::{exit as goodbye, Child as Kid};
use std::thread::sleep as thread_sleep;
#[rustfmt::skip]
use std::{
any::{type_name as ident, Any},
clone as foo,
sync :: Mutex as StdMutie,
};
fn main() {
use std::collections::BTreeMap as Map;
}

View file

@ -1,5 +1,4 @@
//@aux-build:proc_macro_derive.rs:proc-macro
//@run-rustfix
//@aux-build:proc_macro_derive.rs
#![warn(clippy::nonstandard_macro_braces)]

View file

@ -1,5 +1,4 @@
//@aux-build:proc_macro_derive.rs:proc-macro
//@run-rustfix
//@aux-build:proc_macro_derive.rs
#![warn(clippy::nonstandard_macro_braces)]

View file

@ -1,5 +1,5 @@
error: use of irregular braces for `vec!` macro
--> $DIR/conf_nonstandard_macro_braces.rs:44:13
--> $DIR/conf_nonstandard_macro_braces.rs:43:13
|
LL | let _ = vec! {1, 2, 3};
| ^^^^^^^^^^^^^^ help: consider writing: `vec![1, 2, 3]`
@ -7,31 +7,31 @@ LL | let _ = vec! {1, 2, 3};
= note: `-D clippy::nonstandard-macro-braces` implied by `-D warnings`
error: use of irregular braces for `format!` macro
--> $DIR/conf_nonstandard_macro_braces.rs:45:13
--> $DIR/conf_nonstandard_macro_braces.rs:44:13
|
LL | let _ = format!["ugh {} stop being such a good compiler", "hello"];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `format!("ugh {} stop being such a good compiler", "hello")`
error: use of irregular braces for `matches!` macro
--> $DIR/conf_nonstandard_macro_braces.rs:46:13
--> $DIR/conf_nonstandard_macro_braces.rs:45:13
|
LL | let _ = matches!{{}, ()};
| ^^^^^^^^^^^^^^^^ help: consider writing: `matches!({}, ())`
error: use of irregular braces for `quote!` macro
--> $DIR/conf_nonstandard_macro_braces.rs:47:13
--> $DIR/conf_nonstandard_macro_braces.rs:46:13
|
LL | let _ = quote!(let x = 1;);
| ^^^^^^^^^^^^^^^^^^ help: consider writing: `quote!{let x = 1;}`
error: use of irregular braces for `quote::quote!` macro
--> $DIR/conf_nonstandard_macro_braces.rs:48:13
--> $DIR/conf_nonstandard_macro_braces.rs:47:13
|
LL | let _ = quote::quote!(match match match);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `quote::quote!{match match match}`
error: use of irregular braces for `vec!` macro
--> $DIR/conf_nonstandard_macro_braces.rs:19:9
--> $DIR/conf_nonstandard_macro_braces.rs:18:9
|
LL | vec!{0, 0, 0}
| ^^^^^^^^^^^^^ help: consider writing: `vec![0, 0, 0]`
@ -42,13 +42,13 @@ LL | let _ = test!(); // trigger when macro def is inside our own crate
= note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
error: use of irregular braces for `type_pos!` macro
--> $DIR/conf_nonstandard_macro_braces.rs:57:12
--> $DIR/conf_nonstandard_macro_braces.rs:56:12
|
LL | let _: type_pos!(usize) = vec![];
| ^^^^^^^^^^^^^^^^ help: consider writing: `type_pos![usize]`
error: use of irregular braces for `eprint!` macro
--> $DIR/conf_nonstandard_macro_braces.rs:59:5
--> $DIR/conf_nonstandard_macro_braces.rs:58:5
|
LL | eprint!("test if user config overrides defaults");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `eprint!["test if user config overrides defaults"]`

View file

@ -1,4 +1,3 @@
//@run-rustfix
#![allow(
unused,
clippy::unused_unit,

View file

@ -1,4 +1,3 @@
//@run-rustfix
#![allow(
unused,
clippy::unused_unit,

View file

@ -1,5 +1,5 @@
error: consider moving the `;` outside the block for consistent formatting
--> $DIR/both.rs:43:5
--> $DIR/both.rs:42:5
|
LL | { unit_fn_block(); }
| ^^^^^^^^^^^^^^^^^^^^
@ -12,7 +12,7 @@ LL + { unit_fn_block() };
|
error: consider moving the `;` outside the block for consistent formatting
--> $DIR/both.rs:44:5
--> $DIR/both.rs:43:5
|
LL | unsafe { unit_fn_block(); }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -24,7 +24,7 @@ LL + unsafe { unit_fn_block() };
|
error: consider moving the `;` inside the block for consistent formatting
--> $DIR/both.rs:49:5
--> $DIR/both.rs:48:5
|
LL | / {
LL | | unit_fn_block();
@ -40,7 +40,7 @@ LL ~ }
|
error: consider moving the `;` outside the block for consistent formatting
--> $DIR/both.rs:63:5
--> $DIR/both.rs:62:5
|
LL | { m!(()); }
| ^^^^^^^^^^^

View file

@ -1,4 +1,3 @@
//@run-rustfix
#![allow(
unused,
clippy::unused_unit,

View file

@ -1,4 +1,3 @@
//@run-rustfix
#![allow(
unused,
clippy::unused_unit,

View file

@ -1,5 +1,5 @@
error: consider moving the `;` inside the block for consistent formatting
--> $DIR/semicolon_inside_block.rs:48:5
--> $DIR/semicolon_inside_block.rs:47:5
|
LL | / {
LL | | unit_fn_block();

View file

@ -1,4 +1,3 @@
//@run-rustfix
#![allow(
unused,
clippy::unused_unit,

View file

@ -1,4 +1,3 @@
//@run-rustfix
#![allow(
unused,
clippy::unused_unit,

View file

@ -1,5 +1,5 @@
error: consider moving the `;` outside the block for consistent formatting
--> $DIR/semicolon_outside_block.rs:42:5
--> $DIR/semicolon_outside_block.rs:41:5
|
LL | { unit_fn_block(); }
| ^^^^^^^^^^^^^^^^^^^^
@ -12,7 +12,7 @@ LL + { unit_fn_block() };
|
error: consider moving the `;` outside the block for consistent formatting
--> $DIR/semicolon_outside_block.rs:43:5
--> $DIR/semicolon_outside_block.rs:42:5
|
LL | unsafe { unit_fn_block(); }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -24,7 +24,7 @@ LL + unsafe { unit_fn_block() };
|
error: consider moving the `;` outside the block for consistent formatting
--> $DIR/semicolon_outside_block.rs:62:5
--> $DIR/semicolon_outside_block.rs:61:5
|
LL | { m!(()); }
| ^^^^^^^^^^^

View file

@ -1,6 +1,6 @@
//@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)"
//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)"
//@no-rustfix
#![warn(clippy::trivially_copy_pass_by_ref)]
#![allow(clippy::needless_pass_by_ref_mut)]

View file

@ -1,4 +1,4 @@
//@aux-build:proc_macro_unsafe.rs:proc-macro
//@aux-build:proc_macro_unsafe.rs
#![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)]
#![allow(deref_nullptr, clippy::let_unit_value, clippy::missing_safety_doc)]

View file

@ -0,0 +1,95 @@
//@compile-flags: --test
#![allow(
unused_mut,
clippy::get_first,
clippy::from_iter_instead_of_collect,
clippy::useless_vec
)]
#![warn(clippy::unwrap_used)]
#![warn(clippy::get_unwrap)]
use std::collections::{BTreeMap, HashMap, VecDeque};
struct GetFalsePositive {
arr: [u32; 3],
}
impl GetFalsePositive {
fn get(&self, pos: usize) -> Option<&u32> {
self.arr.get(pos)
}
fn get_mut(&mut self, pos: usize) -> Option<&mut u32> {
self.arr.get_mut(pos)
}
}
fn main() {
let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
let mut some_slice = &mut [0, 1, 2, 3];
let mut some_vec = vec![0, 1, 2, 3];
let mut some_vecdeque: VecDeque<_> = some_vec.iter().cloned().collect();
let mut some_hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(1, 'a'), (2, 'b')]);
let mut some_btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(1, 'a'), (2, 'b')]);
let mut false_positive = GetFalsePositive { arr: [0, 1, 2] };
{
// Test `get().unwrap()`
let _ = &boxed_slice[1];
let _ = &some_slice[0];
let _ = &some_vec[0];
let _ = &some_vecdeque[0];
let _ = &some_hashmap[&1];
let _ = &some_btreemap[&1];
#[allow(clippy::unwrap_used)]
let _ = false_positive.get(0).unwrap();
// Test with deref
let _: u8 = boxed_slice[1];
}
{
// Test `get_mut().unwrap()`
boxed_slice[0] = 1;
some_slice[0] = 1;
some_vec[0] = 1;
some_vecdeque[0] = 1;
// Check false positives
#[allow(clippy::unwrap_used)]
{
*some_hashmap.get_mut(&1).unwrap() = 'b';
*some_btreemap.get_mut(&1).unwrap() = 'b';
*false_positive.get_mut(0).unwrap() = 1;
}
}
{
// Test `get().unwrap().foo()` and `get_mut().unwrap().bar()`
let _ = some_vec[0..1].to_vec();
let _ = some_vec[0..1].to_vec();
}
}
#[test]
fn test() {
let boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
let _ = &boxed_slice[1];
}
#[cfg(test)]
mod issue9612 {
// should not lint in `#[cfg(test)]` modules
#[test]
fn test_fn() {
let _a: u8 = 2.try_into().unwrap();
let _a: u8 = 3.try_into().expect("");
util();
}
fn util() {
let _a: u8 = 4.try_into().unwrap();
let _a: u8 = 5.try_into().expect("");
// should still warn
let _ = &Box::new([0])[1];
}
}

View file

@ -0,0 +1,44 @@
#![warn(clippy::upper_case_acronyms)]
struct HttpResponse; // not linted by default, but with cfg option
struct CString; // not linted
enum Flags {
Ns, // not linted
Cwr,
Ece,
Urg,
Ack,
Psh,
Rst,
Syn,
Fin,
}
// linted with cfg option, beware that lint suggests `GccllvmSomething` instead of
// `GccLlvmSomething`
struct GccllvmSomething;
// don't warn on public items
pub struct MIXEDCapital;
pub struct FULLCAPITAL;
// enum variants should not be linted if the num is pub
pub enum ParseError<T> {
FULLCAPITAL(u8),
MIXEDCapital(String),
Utf8(std::string::FromUtf8Error),
Parse(T, String),
}
// private, do lint here
enum ParseErrorPrivate<T> {
Wasd(u8),
WasdMixed(String),
Utf8(std::string::FromUtf8Error),
Parse(T, String),
}
fn main() {}

View file

@ -0,0 +1,16 @@
struct S {
x: u64,
}
struct C {
y: u16,
}
struct Foo(Vec<u8>);
struct Bar(Vec<u16>);
struct Quux(Vec<Box<u32>>);
struct Baz(Vec<Box<(u16, u16)>>);
struct BarBaz(Vec<Box<S>>);
struct FooBarBaz(Vec<C>);
fn main() {}

View file

@ -12,27 +12,46 @@ fn main() {
const Z: u32 = 0;
let u: u32 = 42;
u <= 0;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
u <= Z;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
u < Z;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
Z >= u;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
Z > u;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
u > u32::MAX;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
u >= u32::MAX;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
u32::MAX < u;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
u32::MAX <= u;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
1-1 > u;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
u >= !0;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
u <= 12 - 2*6;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
let i: i8 = 0;
i < -127 - 1;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
i8::MAX >= i;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
3-7 < i32::MIN;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
let b = false;
b >= true;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
false > b;
//~^ ERROR: this comparison involving the minimum or maximum element for this type con
u > 0; // ok
// this is handled by clippy::unit_cmp
() < {};
//~^ ERROR: <-comparison of unit values detected. This will always be false
//~| NOTE: `#[deny(clippy::unit_cmp)]` on by default
}
use std::cmp::{Ordering, PartialEq, PartialOrd};

View file

@ -8,7 +8,7 @@ LL | u <= 0;
= note: `-D clippy::absurd-extreme-comparisons` implied by `-D warnings`
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:15:5
--> $DIR/absurd-extreme-comparisons.rs:16:5
|
LL | u <= Z;
| ^^^^^^
@ -16,7 +16,7 @@ LL | u <= Z;
= help: because `Z` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `u == Z` instead
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:16:5
--> $DIR/absurd-extreme-comparisons.rs:18:5
|
LL | u < Z;
| ^^^^^
@ -24,7 +24,7 @@ LL | u < Z;
= help: because `Z` is the minimum value for this type, this comparison is always false
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:17:5
--> $DIR/absurd-extreme-comparisons.rs:20:5
|
LL | Z >= u;
| ^^^^^^
@ -32,7 +32,7 @@ LL | Z >= u;
= help: because `Z` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `Z == u` instead
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:18:5
--> $DIR/absurd-extreme-comparisons.rs:22:5
|
LL | Z > u;
| ^^^^^
@ -40,7 +40,7 @@ LL | Z > u;
= help: because `Z` is the minimum value for this type, this comparison is always false
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:19:5
--> $DIR/absurd-extreme-comparisons.rs:24:5
|
LL | u > u32::MAX;
| ^^^^^^^^^^^^
@ -48,7 +48,7 @@ LL | u > u32::MAX;
= help: because `u32::MAX` is the maximum value for this type, this comparison is always false
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:20:5
--> $DIR/absurd-extreme-comparisons.rs:26:5
|
LL | u >= u32::MAX;
| ^^^^^^^^^^^^^
@ -56,7 +56,7 @@ LL | u >= u32::MAX;
= help: because `u32::MAX` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `u == u32::MAX` instead
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:21:5
--> $DIR/absurd-extreme-comparisons.rs:28:5
|
LL | u32::MAX < u;
| ^^^^^^^^^^^^
@ -64,7 +64,7 @@ LL | u32::MAX < u;
= help: because `u32::MAX` is the maximum value for this type, this comparison is always false
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:22:5
--> $DIR/absurd-extreme-comparisons.rs:30:5
|
LL | u32::MAX <= u;
| ^^^^^^^^^^^^^
@ -72,7 +72,7 @@ LL | u32::MAX <= u;
= help: because `u32::MAX` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `u32::MAX == u` instead
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:23:5
--> $DIR/absurd-extreme-comparisons.rs:32:5
|
LL | 1-1 > u;
| ^^^^^^^
@ -80,7 +80,7 @@ LL | 1-1 > u;
= help: because `1-1` is the minimum value for this type, this comparison is always false
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:24:5
--> $DIR/absurd-extreme-comparisons.rs:34:5
|
LL | u >= !0;
| ^^^^^^^
@ -88,7 +88,7 @@ LL | u >= !0;
= help: because `!0` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `u == !0` instead
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:25:5
--> $DIR/absurd-extreme-comparisons.rs:36:5
|
LL | u <= 12 - 2*6;
| ^^^^^^^^^^^^^
@ -96,7 +96,7 @@ LL | u <= 12 - 2*6;
= help: because `12 - 2*6` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `u == 12 - 2*6` instead
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:27:5
--> $DIR/absurd-extreme-comparisons.rs:39:5
|
LL | i < -127 - 1;
| ^^^^^^^^^^^^
@ -104,7 +104,7 @@ LL | i < -127 - 1;
= help: because `-127 - 1` is the minimum value for this type, this comparison is always false
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:28:5
--> $DIR/absurd-extreme-comparisons.rs:41:5
|
LL | i8::MAX >= i;
| ^^^^^^^^^^^^
@ -112,7 +112,7 @@ LL | i8::MAX >= i;
= help: because `i8::MAX` is the maximum value for this type, this comparison is always true
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:29:5
--> $DIR/absurd-extreme-comparisons.rs:43:5
|
LL | 3-7 < i32::MIN;
| ^^^^^^^^^^^^^^
@ -120,7 +120,7 @@ LL | 3-7 < i32::MIN;
= help: because `i32::MIN` is the minimum value for this type, this comparison is always false
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:31:5
--> $DIR/absurd-extreme-comparisons.rs:46:5
|
LL | b >= true;
| ^^^^^^^^^
@ -128,7 +128,7 @@ LL | b >= true;
= help: because `true` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `b == true` instead
error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
--> $DIR/absurd-extreme-comparisons.rs:32:5
--> $DIR/absurd-extreme-comparisons.rs:48:5
|
LL | false > b;
| ^^^^^^^^^
@ -136,7 +136,7 @@ LL | false > b;
= help: because `false` is the minimum value for this type, this comparison is always false
error: <-comparison of unit values detected. This will always be false
--> $DIR/absurd-extreme-comparisons.rs:35:5
--> $DIR/absurd-extreme-comparisons.rs:52:5
|
LL | () < {};
| ^^^^^^^

View file

@ -1,5 +1,4 @@
//@run-rustfix
//@aux-build:proc_macros.rs:proc-macro
//@aux-build:proc_macros.rs
#![allow(unused)]
#![warn(clippy::allow_attributes)]
#![feature(lint_reasons)]

View file

@ -1,5 +1,4 @@
//@run-rustfix
//@aux-build:proc_macros.rs:proc-macro
//@aux-build:proc_macros.rs
#![allow(unused)]
#![warn(clippy::allow_attributes)]
#![feature(lint_reasons)]

View file

@ -1,5 +1,5 @@
error: #[allow] attribute found
--> $DIR/allow_attributes.rs:14:3
--> $DIR/allow_attributes.rs:13:3
|
LL | #[allow(dead_code)]
| ^^^^^ help: replace it with: `expect`
@ -7,7 +7,7 @@ LL | #[allow(dead_code)]
= note: `-D clippy::allow-attributes` implied by `-D warnings`
error: #[allow] attribute found
--> $DIR/allow_attributes.rs:23:30
--> $DIR/allow_attributes.rs:22:30
|
LL | #[cfg_attr(panic = "unwind", allow(dead_code))]
| ^^^^^ help: replace it with: `expect`

View file

@ -1,4 +1,4 @@
//@aux-build:proc_macros.rs:proc-macro
//@aux-build:proc_macros.rs
#![feature(lint_reasons)]
#![deny(clippy::allow_attributes_without_reason)]
#![allow(unfulfilled_lint_expectations)]

View file

@ -1,6 +1,5 @@
//@run-rustfix
//@edition:2018
//@aux-build:proc_macros.rs:proc-macro
//@aux-build:proc_macros.rs
#![feature(exclusive_range_pattern)]
#![feature(stmt_expr_attributes)]

View file

@ -1,6 +1,5 @@
//@run-rustfix
//@edition:2018
//@aux-build:proc_macros.rs:proc-macro
//@aux-build:proc_macros.rs
#![feature(exclusive_range_pattern)]
#![feature(stmt_expr_attributes)]

View file

@ -1,5 +1,5 @@
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:19:17
--> $DIR/almost_complete_range.rs:18:17
|
LL | let _ = ('a') ..'z';
| ^^^^^^--^^^
@ -9,7 +9,7 @@ LL | let _ = ('a') ..'z';
= note: `-D clippy::almost-complete-range` implied by `-D warnings`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:20:17
--> $DIR/almost_complete_range.rs:19:17
|
LL | let _ = 'A' .. ('Z');
| ^^^^--^^^^^^
@ -17,7 +17,7 @@ LL | let _ = 'A' .. ('Z');
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:21:17
--> $DIR/almost_complete_range.rs:20:17
|
LL | let _ = ((('0'))) .. ('9');
| ^^^^^^^^^^--^^^^^^
@ -25,7 +25,7 @@ LL | let _ = ((('0'))) .. ('9');
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:28:13
--> $DIR/almost_complete_range.rs:27:13
|
LL | let _ = (b'a')..(b'z');
| ^^^^^^--^^^^^^
@ -33,7 +33,7 @@ LL | let _ = (b'a')..(b'z');
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:29:13
--> $DIR/almost_complete_range.rs:28:13
|
LL | let _ = b'A'..b'Z';
| ^^^^--^^^^
@ -41,7 +41,7 @@ LL | let _ = b'A'..b'Z';
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:30:13
--> $DIR/almost_complete_range.rs:29:13
|
LL | let _ = b'0'..b'9';
| ^^^^--^^^^
@ -49,7 +49,7 @@ LL | let _ = b'0'..b'9';
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:36:13
--> $DIR/almost_complete_range.rs:35:13
|
LL | let _ = inline!('a')..'z';
| ^^^^^^^^^^^^--^^^
@ -57,7 +57,7 @@ LL | let _ = inline!('a')..'z';
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:37:13
--> $DIR/almost_complete_range.rs:36:13
|
LL | let _ = inline!('A')..'Z';
| ^^^^^^^^^^^^--^^^
@ -65,7 +65,7 @@ LL | let _ = inline!('A')..'Z';
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:38:13
--> $DIR/almost_complete_range.rs:37:13
|
LL | let _ = inline!('0')..'9';
| ^^^^^^^^^^^^--^^^
@ -73,7 +73,7 @@ LL | let _ = inline!('0')..'9';
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:41:9
--> $DIR/almost_complete_range.rs:40:9
|
LL | b'a'..b'z' if true => 1,
| ^^^^--^^^^
@ -81,7 +81,7 @@ LL | b'a'..b'z' if true => 1,
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:42:9
--> $DIR/almost_complete_range.rs:41:9
|
LL | b'A'..b'Z' if true => 2,
| ^^^^--^^^^
@ -89,7 +89,7 @@ LL | b'A'..b'Z' if true => 2,
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:43:9
--> $DIR/almost_complete_range.rs:42:9
|
LL | b'0'..b'9' if true => 3,
| ^^^^--^^^^
@ -97,7 +97,7 @@ LL | b'0'..b'9' if true => 3,
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:51:9
--> $DIR/almost_complete_range.rs:50:9
|
LL | 'a'..'z' if true => 1,
| ^^^--^^^
@ -105,7 +105,7 @@ LL | 'a'..'z' if true => 1,
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:52:9
--> $DIR/almost_complete_range.rs:51:9
|
LL | 'A'..'Z' if true => 2,
| ^^^--^^^
@ -113,7 +113,7 @@ LL | 'A'..'Z' if true => 2,
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:53:9
--> $DIR/almost_complete_range.rs:52:9
|
LL | '0'..'9' if true => 3,
| ^^^--^^^
@ -121,7 +121,7 @@ LL | '0'..'9' if true => 3,
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:66:17
--> $DIR/almost_complete_range.rs:65:17
|
LL | let _ = 'a'..'z';
| ^^^--^^^
@ -131,7 +131,7 @@ LL | let _ = 'a'..'z';
= note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:67:17
--> $DIR/almost_complete_range.rs:66:17
|
LL | let _ = 'A'..'Z';
| ^^^--^^^
@ -141,7 +141,7 @@ LL | let _ = 'A'..'Z';
= note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:68:17
--> $DIR/almost_complete_range.rs:67:17
|
LL | let _ = '0'..'9';
| ^^^--^^^
@ -151,7 +151,7 @@ LL | let _ = '0'..'9';
= note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:75:9
--> $DIR/almost_complete_range.rs:74:9
|
LL | 'a'..'z' => 1,
| ^^^--^^^
@ -159,7 +159,7 @@ LL | 'a'..'z' => 1,
| help: use an inclusive range: `...`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:76:9
--> $DIR/almost_complete_range.rs:75:9
|
LL | 'A'..'Z' => 2,
| ^^^--^^^
@ -167,7 +167,7 @@ LL | 'A'..'Z' => 2,
| help: use an inclusive range: `...`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:77:9
--> $DIR/almost_complete_range.rs:76:9
|
LL | '0'..'9' => 3,
| ^^^--^^^
@ -175,7 +175,7 @@ LL | '0'..'9' => 3,
| help: use an inclusive range: `...`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:84:13
--> $DIR/almost_complete_range.rs:83:13
|
LL | let _ = 'a'..'z';
| ^^^--^^^
@ -183,7 +183,7 @@ LL | let _ = 'a'..'z';
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:85:13
--> $DIR/almost_complete_range.rs:84:13
|
LL | let _ = 'A'..'Z';
| ^^^--^^^
@ -191,7 +191,7 @@ LL | let _ = 'A'..'Z';
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:86:13
--> $DIR/almost_complete_range.rs:85:13
|
LL | let _ = '0'..'9';
| ^^^--^^^
@ -199,7 +199,7 @@ LL | let _ = '0'..'9';
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:88:9
--> $DIR/almost_complete_range.rs:87:9
|
LL | 'a'..'z' => 1,
| ^^^--^^^
@ -207,7 +207,7 @@ LL | 'a'..'z' => 1,
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:89:9
--> $DIR/almost_complete_range.rs:88:9
|
LL | 'A'..'Z' => 1,
| ^^^--^^^
@ -215,7 +215,7 @@ LL | 'A'..'Z' => 1,
| help: use an inclusive range: `..=`
error: almost complete ascii range
--> $DIR/almost_complete_range.rs:90:9
--> $DIR/almost_complete_range.rs:89:9
|
LL | '0'..'9' => 3,
| ^^^--^^^

View file

@ -2,63 +2,86 @@
#[allow(clippy::similar_names)]
fn main() {
let my_e = 2.7182;
//~^ ERROR: approximate value of `f{32, 64}::consts::E` found
let almost_e = 2.718;
//~^ ERROR: approximate value of `f{32, 64}::consts::E` found
let no_e = 2.71;
let my_1_frac_pi = 0.3183;
//~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_1_PI` found
let no_1_frac_pi = 0.31;
let my_frac_1_sqrt_2 = 0.70710678;
//~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found
let almost_frac_1_sqrt_2 = 0.70711;
//~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found
let my_frac_1_sqrt_2 = 0.707;
let my_frac_2_pi = 0.63661977;
//~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_2_PI` found
let no_frac_2_pi = 0.636;
let my_frac_2_sq_pi = 1.128379;
//~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_2_SQRT_PI` found
let no_frac_2_sq_pi = 1.128;
let my_frac_pi_2 = 1.57079632679;
//~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_PI_2` found
let no_frac_pi_2 = 1.5705;
let my_frac_pi_3 = 1.04719755119;
//~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_PI_3` found
let no_frac_pi_3 = 1.047;
let my_frac_pi_4 = 0.785398163397;
//~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_PI_4` found
let no_frac_pi_4 = 0.785;
let my_frac_pi_6 = 0.523598775598;
//~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_PI_6` found
let no_frac_pi_6 = 0.523;
let my_frac_pi_8 = 0.3926990816987;
//~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_PI_8` found
let no_frac_pi_8 = 0.392;
let my_ln_10 = 2.302585092994046;
//~^ ERROR: approximate value of `f{32, 64}::consts::LN_10` found
let no_ln_10 = 2.303;
let my_ln_2 = 0.6931471805599453;
//~^ ERROR: approximate value of `f{32, 64}::consts::LN_2` found
let no_ln_2 = 0.693;
let my_log10_e = 0.4342944819032518;
//~^ ERROR: approximate value of `f{32, 64}::consts::LOG10_E` found
let no_log10_e = 0.434;
let my_log2_e = 1.4426950408889634;
//~^ ERROR: approximate value of `f{32, 64}::consts::LOG2_E` found
let no_log2_e = 1.442;
let log2_10 = 3.321928094887362;
//~^ ERROR: approximate value of `f{32, 64}::consts::LOG2_10` found
let no_log2_10 = 3.321;
let log10_2 = 0.301029995663981;
//~^ ERROR: approximate value of `f{32, 64}::consts::LOG10_2` found
let no_log10_2 = 0.301;
let my_pi = 3.1415;
//~^ ERROR: approximate value of `f{32, 64}::consts::PI` found
let almost_pi = 3.14;
//~^ ERROR: approximate value of `f{32, 64}::consts::PI` found
let no_pi = 3.15;
let my_sq2 = 1.4142;
//~^ ERROR: approximate value of `f{32, 64}::consts::SQRT_2` found
let no_sq2 = 1.414;
let my_tau = 6.2832;
//~^ ERROR: approximate value of `f{32, 64}::consts::TAU` found
let almost_tau = 6.28;
//~^ ERROR: approximate value of `f{32, 64}::consts::TAU` found
let no_tau = 6.3;
}

View file

@ -8,7 +8,7 @@ LL | let my_e = 2.7182;
= note: `-D clippy::approx-constant` implied by `-D warnings`
error: approximate value of `f{32, 64}::consts::E` found
--> $DIR/approx_const.rs:5:20
--> $DIR/approx_const.rs:6:20
|
LL | let almost_e = 2.718;
| ^^^^^
@ -16,7 +16,7 @@ LL | let almost_e = 2.718;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::FRAC_1_PI` found
--> $DIR/approx_const.rs:8:24
--> $DIR/approx_const.rs:10:24
|
LL | let my_1_frac_pi = 0.3183;
| ^^^^^^
@ -24,7 +24,7 @@ LL | let my_1_frac_pi = 0.3183;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found
--> $DIR/approx_const.rs:11:28
--> $DIR/approx_const.rs:14:28
|
LL | let my_frac_1_sqrt_2 = 0.70710678;
| ^^^^^^^^^^
@ -32,7 +32,7 @@ LL | let my_frac_1_sqrt_2 = 0.70710678;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found
--> $DIR/approx_const.rs:12:32
--> $DIR/approx_const.rs:16:32
|
LL | let almost_frac_1_sqrt_2 = 0.70711;
| ^^^^^^^
@ -40,7 +40,7 @@ LL | let almost_frac_1_sqrt_2 = 0.70711;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::FRAC_2_PI` found
--> $DIR/approx_const.rs:15:24
--> $DIR/approx_const.rs:20:24
|
LL | let my_frac_2_pi = 0.63661977;
| ^^^^^^^^^^
@ -48,7 +48,7 @@ LL | let my_frac_2_pi = 0.63661977;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::FRAC_2_SQRT_PI` found
--> $DIR/approx_const.rs:18:27
--> $DIR/approx_const.rs:24:27
|
LL | let my_frac_2_sq_pi = 1.128379;
| ^^^^^^^^
@ -56,7 +56,7 @@ LL | let my_frac_2_sq_pi = 1.128379;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::FRAC_PI_2` found
--> $DIR/approx_const.rs:21:24
--> $DIR/approx_const.rs:28:24
|
LL | let my_frac_pi_2 = 1.57079632679;
| ^^^^^^^^^^^^^
@ -64,7 +64,7 @@ LL | let my_frac_pi_2 = 1.57079632679;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::FRAC_PI_3` found
--> $DIR/approx_const.rs:24:24
--> $DIR/approx_const.rs:32:24
|
LL | let my_frac_pi_3 = 1.04719755119;
| ^^^^^^^^^^^^^
@ -72,7 +72,7 @@ LL | let my_frac_pi_3 = 1.04719755119;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::FRAC_PI_4` found
--> $DIR/approx_const.rs:27:24
--> $DIR/approx_const.rs:36:24
|
LL | let my_frac_pi_4 = 0.785398163397;
| ^^^^^^^^^^^^^^
@ -80,7 +80,7 @@ LL | let my_frac_pi_4 = 0.785398163397;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::FRAC_PI_6` found
--> $DIR/approx_const.rs:30:24
--> $DIR/approx_const.rs:40:24
|
LL | let my_frac_pi_6 = 0.523598775598;
| ^^^^^^^^^^^^^^
@ -88,7 +88,7 @@ LL | let my_frac_pi_6 = 0.523598775598;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::FRAC_PI_8` found
--> $DIR/approx_const.rs:33:24
--> $DIR/approx_const.rs:44:24
|
LL | let my_frac_pi_8 = 0.3926990816987;
| ^^^^^^^^^^^^^^^
@ -96,7 +96,7 @@ LL | let my_frac_pi_8 = 0.3926990816987;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::LN_10` found
--> $DIR/approx_const.rs:36:20
--> $DIR/approx_const.rs:48:20
|
LL | let my_ln_10 = 2.302585092994046;
| ^^^^^^^^^^^^^^^^^
@ -104,7 +104,7 @@ LL | let my_ln_10 = 2.302585092994046;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::LN_2` found
--> $DIR/approx_const.rs:39:19
--> $DIR/approx_const.rs:52:19
|
LL | let my_ln_2 = 0.6931471805599453;
| ^^^^^^^^^^^^^^^^^^
@ -112,7 +112,7 @@ LL | let my_ln_2 = 0.6931471805599453;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::LOG10_E` found
--> $DIR/approx_const.rs:42:22
--> $DIR/approx_const.rs:56:22
|
LL | let my_log10_e = 0.4342944819032518;
| ^^^^^^^^^^^^^^^^^^
@ -120,7 +120,7 @@ LL | let my_log10_e = 0.4342944819032518;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::LOG2_E` found
--> $DIR/approx_const.rs:45:21
--> $DIR/approx_const.rs:60:21
|
LL | let my_log2_e = 1.4426950408889634;
| ^^^^^^^^^^^^^^^^^^
@ -128,7 +128,7 @@ LL | let my_log2_e = 1.4426950408889634;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::LOG2_10` found
--> $DIR/approx_const.rs:48:19
--> $DIR/approx_const.rs:64:19
|
LL | let log2_10 = 3.321928094887362;
| ^^^^^^^^^^^^^^^^^
@ -136,7 +136,7 @@ LL | let log2_10 = 3.321928094887362;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::LOG10_2` found
--> $DIR/approx_const.rs:51:19
--> $DIR/approx_const.rs:68:19
|
LL | let log10_2 = 0.301029995663981;
| ^^^^^^^^^^^^^^^^^
@ -144,7 +144,7 @@ LL | let log10_2 = 0.301029995663981;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::PI` found
--> $DIR/approx_const.rs:54:17
--> $DIR/approx_const.rs:72:17
|
LL | let my_pi = 3.1415;
| ^^^^^^
@ -152,7 +152,7 @@ LL | let my_pi = 3.1415;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::PI` found
--> $DIR/approx_const.rs:55:21
--> $DIR/approx_const.rs:74:21
|
LL | let almost_pi = 3.14;
| ^^^^
@ -160,7 +160,7 @@ LL | let almost_pi = 3.14;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::SQRT_2` found
--> $DIR/approx_const.rs:58:18
--> $DIR/approx_const.rs:78:18
|
LL | let my_sq2 = 1.4142;
| ^^^^^^
@ -168,7 +168,7 @@ LL | let my_sq2 = 1.4142;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::TAU` found
--> $DIR/approx_const.rs:61:18
--> $DIR/approx_const.rs:82:18
|
LL | let my_tau = 6.2832;
| ^^^^^^
@ -176,7 +176,7 @@ LL | let my_tau = 6.2832;
= help: consider using the constant directly
error: approximate value of `f{32, 64}::consts::TAU` found
--> $DIR/approx_const.rs:62:22
--> $DIR/approx_const.rs:84:22
|
LL | let almost_tau = 6.28;
| ^^^^

View file

@ -1,4 +1,4 @@
//@aux-build:proc_macros.rs:proc-macro
//@aux-build:proc_macros.rs
#![warn(clippy::arc_with_non_send_sync)]
#![allow(unused_variables)]

View file

@ -1,4 +1,4 @@
//@aux-build:proc_macro_derive.rs:proc-macro
//@aux-build:proc_macro_derive.rs
#![allow(
clippy::assign_op_pattern,

Some files were not shown because too many files have changed in this diff Show more