mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-27 23:20:39 +00:00
Merge remote-tracking branch 'upstream/master' into rustup
This commit is contained in:
commit
c6408a47bd
111 changed files with 6361 additions and 3311 deletions
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
name: Bug Report
|
name: Bug Report
|
||||||
about: Create a bug report for Clippy
|
about: Create a bug report for Clippy
|
||||||
labels: L-bug
|
labels: C-bug
|
||||||
---
|
---
|
||||||
<!--
|
<!--
|
||||||
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
|
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/false_negative.md
vendored
2
.github/ISSUE_TEMPLATE/false_negative.md
vendored
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
name: Bug Report (False Negative)
|
name: Bug Report (False Negative)
|
||||||
about: Create a bug report about missing warnings from a lint
|
about: Create a bug report about missing warnings from a lint
|
||||||
labels: L-bug, L-false-negative
|
labels: C-bug, I-false-negative
|
||||||
---
|
---
|
||||||
<!--
|
<!--
|
||||||
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
|
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/false_positive.md
vendored
2
.github/ISSUE_TEMPLATE/false_positive.md
vendored
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
name: Bug Report (False Positive)
|
name: Bug Report (False Positive)
|
||||||
about: Create a bug report about a wrongly emitted lint warning
|
about: Create a bug report about a wrongly emitted lint warning
|
||||||
labels: L-bug, L-false-positive
|
labels: C-bug, I-false-positive
|
||||||
---
|
---
|
||||||
<!--
|
<!--
|
||||||
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
|
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/ice.md
vendored
2
.github/ISSUE_TEMPLATE/ice.md
vendored
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
name: Internal Compiler Error
|
name: Internal Compiler Error
|
||||||
about: Create a report for an internal compiler error in Clippy.
|
about: Create a report for an internal compiler error in Clippy.
|
||||||
labels: L-bug, L-crash
|
labels: C-bug, I-ICE
|
||||||
---
|
---
|
||||||
<!--
|
<!--
|
||||||
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
|
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/new_lint.md
vendored
2
.github/ISSUE_TEMPLATE/new_lint.md
vendored
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
name: New lint suggestion
|
name: New lint suggestion
|
||||||
about: Suggest a new Clippy lint.
|
about: Suggest a new Clippy lint.
|
||||||
labels: L-lint
|
labels: A-lint
|
||||||
---
|
---
|
||||||
|
|
||||||
### What it does
|
### What it does
|
||||||
|
|
12
.github/workflows/clippy.yml
vendored
12
.github/workflows/clippy.yml
vendored
|
@ -53,16 +53,8 @@ jobs:
|
||||||
- name: Test "--fix -Zunstable-options"
|
- name: Test "--fix -Zunstable-options"
|
||||||
run: cargo run --features deny-warnings,internal-lints --bin cargo-clippy -- clippy --fix -Zunstable-options
|
run: cargo run --features deny-warnings,internal-lints --bin cargo-clippy -- clippy --fix -Zunstable-options
|
||||||
|
|
||||||
- name: Test
|
- name: Test Workspace
|
||||||
run: cargo test --features deny-warnings,internal-lints
|
run: cargo test --all --features deny-warnings,internal-lints
|
||||||
|
|
||||||
- name: Test clippy_lints
|
|
||||||
run: cargo test --features deny-warnings,internal-lints
|
|
||||||
working-directory: clippy_lints
|
|
||||||
|
|
||||||
- name: Test rustc_tools_util
|
|
||||||
run: cargo test --features deny-warnings
|
|
||||||
working-directory: rustc_tools_util
|
|
||||||
|
|
||||||
- name: Test clippy_dev
|
- name: Test clippy_dev
|
||||||
run: cargo test --features deny-warnings
|
run: cargo test --features deny-warnings
|
||||||
|
|
12
.github/workflows/clippy_bors.yml
vendored
12
.github/workflows/clippy_bors.yml
vendored
|
@ -112,16 +112,8 @@ jobs:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cargo build --features deny-warnings,internal-lints
|
run: cargo build --features deny-warnings,internal-lints
|
||||||
|
|
||||||
- name: Test
|
- name: Test Workspace
|
||||||
run: cargo test --features deny-warnings,internal-lints
|
run: cargo test --all --features deny-warnings,internal-lints
|
||||||
|
|
||||||
- name: Test clippy_lints
|
|
||||||
run: cargo test --features deny-warnings,internal-lints
|
|
||||||
working-directory: clippy_lints
|
|
||||||
|
|
||||||
- name: Test rustc_tools_util
|
|
||||||
run: cargo test --features deny-warnings
|
|
||||||
working-directory: rustc_tools_util
|
|
||||||
|
|
||||||
- name: Test clippy_dev
|
- name: Test clippy_dev
|
||||||
run: cargo test --features deny-warnings
|
run: cargo test --features deny-warnings
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -18,6 +18,7 @@ out
|
||||||
*Cargo.lock
|
*Cargo.lock
|
||||||
/target
|
/target
|
||||||
/clippy_lints/target
|
/clippy_lints/target
|
||||||
|
/clippy_utils/target
|
||||||
/clippy_workspace_tests/target
|
/clippy_workspace_tests/target
|
||||||
/clippy_dev/target
|
/clippy_dev/target
|
||||||
/rustc_tools_util/target
|
/rustc_tools_util/target
|
||||||
|
|
129
CHANGELOG.md
129
CHANGELOG.md
|
@ -6,13 +6,128 @@ document.
|
||||||
|
|
||||||
## Unreleased / In Rust Nightly
|
## Unreleased / In Rust Nightly
|
||||||
|
|
||||||
[4911ab1...master](https://github.com/rust-lang/rust-clippy/compare/4911ab1...master)
|
[3e41797...master](https://github.com/rust-lang/rust-clippy/compare/3e41797...master)
|
||||||
|
|
||||||
|
## Rust 1.51
|
||||||
|
|
||||||
|
Current beta, release 2021-03-25
|
||||||
|
|
||||||
|
[4911ab1...3e41797](https://github.com/rust-lang/rust-clippy/compare/4911ab1...3e41797)
|
||||||
|
|
||||||
|
### New Lints
|
||||||
|
|
||||||
|
* [`upper_case_acronyms`]
|
||||||
|
[#6475](https://github.com/rust-lang/rust-clippy/pull/6475)
|
||||||
|
* [`from_over_into`] [#6476](https://github.com/rust-lang/rust-clippy/pull/6476)
|
||||||
|
* [`case_sensitive_file_extension_comparisons`]
|
||||||
|
[#6500](https://github.com/rust-lang/rust-clippy/pull/6500)
|
||||||
|
* [`needless_question_mark`]
|
||||||
|
[#6507](https://github.com/rust-lang/rust-clippy/pull/6507)
|
||||||
|
* [`missing_panics_doc`]
|
||||||
|
[#6523](https://github.com/rust-lang/rust-clippy/pull/6523)
|
||||||
|
* [`redundant_slicing`]
|
||||||
|
[#6528](https://github.com/rust-lang/rust-clippy/pull/6528)
|
||||||
|
* [`vec_init_then_push`]
|
||||||
|
[#6538](https://github.com/rust-lang/rust-clippy/pull/6538)
|
||||||
|
* [`ptr_as_ptr`] [#6542](https://github.com/rust-lang/rust-clippy/pull/6542)
|
||||||
|
* [`collapsible_else_if`] (split out from `collapsible_if`)
|
||||||
|
[#6544](https://github.com/rust-lang/rust-clippy/pull/6544)
|
||||||
|
* [`inspect_for_each`] [#6577](https://github.com/rust-lang/rust-clippy/pull/6577)
|
||||||
|
* [`manual_filter_map`]
|
||||||
|
[#6591](https://github.com/rust-lang/rust-clippy/pull/6591)
|
||||||
|
* [`exhaustive_enums`]
|
||||||
|
[#6617](https://github.com/rust-lang/rust-clippy/pull/6617)
|
||||||
|
* [`exhaustive_structs`]
|
||||||
|
[#6617](https://github.com/rust-lang/rust-clippy/pull/6617)
|
||||||
|
|
||||||
|
### Moves and Deprecations
|
||||||
|
|
||||||
|
* Replace [`find_map`] with [`manual_find_map`]
|
||||||
|
[#6591](https://github.com/rust-lang/rust-clippy/pull/6591)
|
||||||
|
* [`unknown_clippy_lints`] Now integrated in the `unknown_lints` rustc lint
|
||||||
|
[#6653](https://github.com/rust-lang/rust-clippy/pull/6653)
|
||||||
|
|
||||||
|
### Enhancements
|
||||||
|
|
||||||
|
* [`ptr_arg`] Now also suggests to use `&Path` instead of `&PathBuf`
|
||||||
|
[#6506](https://github.com/rust-lang/rust-clippy/pull/6506)
|
||||||
|
* [`cast_ptr_alignment`] Also lint when the `pointer::cast` method is used
|
||||||
|
[#6557](https://github.com/rust-lang/rust-clippy/pull/6557)
|
||||||
|
* [`collapsible_match`] Now also deals with `&` and `*` operators in the `match`
|
||||||
|
scrutinee [#6619](https://github.com/rust-lang/rust-clippy/pull/6619)
|
||||||
|
|
||||||
|
### False Positive Fixes
|
||||||
|
|
||||||
|
* [`similar_names`] Ignore underscore prefixed names
|
||||||
|
[#6403](https://github.com/rust-lang/rust-clippy/pull/6403)
|
||||||
|
* [`print_literal`] and [`write_literal`] No longer lint numeric literals
|
||||||
|
[#6408](https://github.com/rust-lang/rust-clippy/pull/6408)
|
||||||
|
* [`large_enum_variant`] No longer lints in external macros
|
||||||
|
[#6485](https://github.com/rust-lang/rust-clippy/pull/6485)
|
||||||
|
* [`empty_enum`] Only lint if `never_type` feature is enabled
|
||||||
|
[#6513](https://github.com/rust-lang/rust-clippy/pull/6513)
|
||||||
|
* [`field_reassign_with_default`] No longer lints in macros
|
||||||
|
[#6553](https://github.com/rust-lang/rust-clippy/pull/6553)
|
||||||
|
* [`size_of_in_element_count`] No longer lints when dividing by element size
|
||||||
|
[#6578](https://github.com/rust-lang/rust-clippy/pull/6578)
|
||||||
|
* [`needless_return`] No longer lints in macros
|
||||||
|
[#6586](https://github.com/rust-lang/rust-clippy/pull/6586)
|
||||||
|
* [`match_overlapping_arm`] No longer lint when first arm is completely included
|
||||||
|
in second arm [#6603](https://github.com/rust-lang/rust-clippy/pull/6603)
|
||||||
|
* [`doc_markdown`] Add `WebGL` to the default configuration as an allowed
|
||||||
|
identifier [#6605](https://github.com/rust-lang/rust-clippy/pull/6605)
|
||||||
|
|
||||||
|
### Suggestion Fixes/Improvements
|
||||||
|
|
||||||
|
* [`field_reassign_with_default`] Don't expand macro in lint suggestion
|
||||||
|
[#6531](https://github.com/rust-lang/rust-clippy/pull/6531)
|
||||||
|
* [`match_like_matches_macro`] Strip references in suggestion
|
||||||
|
[#6532](https://github.com/rust-lang/rust-clippy/pull/6532)
|
||||||
|
* [`single_match`] Suggest `if` over `if let` when possible
|
||||||
|
[#6574](https://github.com/rust-lang/rust-clippy/pull/6574)
|
||||||
|
* [`ref_in_deref`] Use parentheses correctly in suggestion
|
||||||
|
[#6609](https://github.com/rust-lang/rust-clippy/pull/6609)
|
||||||
|
* [`stable_sort_primitive`] Clarify error message
|
||||||
|
[#6611](https://github.com/rust-lang/rust-clippy/pull/6611)
|
||||||
|
|
||||||
|
### ICE Fixes
|
||||||
|
|
||||||
|
* [`zero_sized_map_values`]
|
||||||
|
[#6582](https://github.com/rust-lang/rust-clippy/pull/6582)
|
||||||
|
|
||||||
|
### Documentation Improvements
|
||||||
|
|
||||||
|
* Improve search performance on the Clippy website and make it possible to
|
||||||
|
directly search for lints on the GitHub issue tracker
|
||||||
|
[#6483](https://github.com/rust-lang/rust-clippy/pull/6483)
|
||||||
|
* Clean up `README.md` by removing outdated paragraph
|
||||||
|
[#6488](https://github.com/rust-lang/rust-clippy/pull/6488)
|
||||||
|
* [`await_holding_refcell_ref`] and [`await_holding_lock`]
|
||||||
|
[#6585](https://github.com/rust-lang/rust-clippy/pull/6585)
|
||||||
|
* [`as_conversions`] [#6608](https://github.com/rust-lang/rust-clippy/pull/6608)
|
||||||
|
|
||||||
|
### Others
|
||||||
|
|
||||||
|
* Clippy now has a [Roadmap] for 2021. If you like to get involved in a bigger
|
||||||
|
project, take a look at the [Roadmap project page]. All issues listed there
|
||||||
|
are actively mentored
|
||||||
|
[#6462](https://github.com/rust-lang/rust-clippy/pull/6462)
|
||||||
|
* The Clippy version number now corresponds to the Rust version number
|
||||||
|
[#6526](https://github.com/rust-lang/rust-clippy/pull/6526)
|
||||||
|
* Fix oversight which caused Clippy to lint deps in some environments, where
|
||||||
|
`CLIPPY_TESTS=true` was set somewhere
|
||||||
|
[#6575](https://github.com/rust-lang/rust-clippy/pull/6575)
|
||||||
|
* Add `cargo dev-lintcheck` tool to the Clippy Dev Tool
|
||||||
|
[#6469](https://github.com/rust-lang/rust-clippy/pull/6469)
|
||||||
|
|
||||||
|
[Roadmap]: https://github.com/rust-lang/rust-clippy/blob/master/doc/roadmap-2021.md
|
||||||
|
[Roadmap project page]: https://github.com/rust-lang/rust-clippy/projects/3
|
||||||
|
|
||||||
## Rust 1.50
|
## Rust 1.50
|
||||||
|
|
||||||
Current beta, release 2021-02-11
|
Current stable, released 2021-02-11
|
||||||
|
|
||||||
[b20d4c1...4911ab1](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...4911ab1)
|
[b20d4c1...4bd77a1](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...4bd77a1)
|
||||||
|
|
||||||
### New Lints
|
### New Lints
|
||||||
|
|
||||||
|
@ -90,6 +205,8 @@ Current beta, release 2021-02-11
|
||||||
* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]:
|
* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]:
|
||||||
Both now ignore enums with frozen variants
|
Both now ignore enums with frozen variants
|
||||||
[#6110](https://github.com/rust-lang/rust-clippy/pull/6110)
|
[#6110](https://github.com/rust-lang/rust-clippy/pull/6110)
|
||||||
|
* [`field_reassign_with_default`] No longer lint for private fields
|
||||||
|
[#6537](https://github.com/rust-lang/rust-clippy/pull/6537)
|
||||||
|
|
||||||
|
|
||||||
### Suggestion Fixes/Improvements
|
### Suggestion Fixes/Improvements
|
||||||
|
@ -137,7 +254,7 @@ Current beta, release 2021-02-11
|
||||||
|
|
||||||
## Rust 1.49
|
## Rust 1.49
|
||||||
|
|
||||||
Current stable, released 2020-12-31
|
Released 2020-12-31
|
||||||
|
|
||||||
[e636b88...b20d4c1](https://github.com/rust-lang/rust-clippy/compare/e636b88...b20d4c1)
|
[e636b88...b20d4c1](https://github.com/rust-lang/rust-clippy/compare/e636b88...b20d4c1)
|
||||||
|
|
||||||
|
@ -1910,6 +2027,7 @@ Released 2018-09-13
|
||||||
[`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
|
[`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
|
||||||
[`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
|
[`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
|
||||||
[`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
|
[`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
|
||||||
|
[`default_numeric_fallback`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback
|
||||||
[`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access
|
[`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access
|
||||||
[`deprecated_cfg_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr
|
[`deprecated_cfg_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr
|
||||||
[`deprecated_semver`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_semver
|
[`deprecated_semver`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_semver
|
||||||
|
@ -1975,6 +2093,7 @@ Released 2018-09-13
|
||||||
[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
|
[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
|
||||||
[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
|
[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
|
||||||
[`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
|
[`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
|
||||||
|
[`from_str_radix_10`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_str_radix_10
|
||||||
[`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
|
[`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
|
||||||
[`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
|
[`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
|
||||||
[`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
|
[`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
|
||||||
|
@ -1990,6 +2109,7 @@ Released 2018-09-13
|
||||||
[`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub
|
[`implicit_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_saturating_sub
|
||||||
[`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops
|
[`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
|
[`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping
|
||||||
|
[`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor
|
||||||
[`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing
|
[`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing
|
||||||
[`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask
|
[`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask
|
||||||
[`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string
|
[`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string
|
||||||
|
@ -2042,6 +2162,7 @@ Released 2018-09-13
|
||||||
[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
|
[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
|
||||||
[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
|
[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
|
||||||
[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
|
[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
|
||||||
|
[`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
|
||||||
[`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
|
[`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
|
||||||
[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
|
[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
|
||||||
[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
|
[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
|
||||||
|
|
|
@ -18,6 +18,9 @@ build = "build.rs"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
exclude = ["clippy_dev", "mini-macro", "target/lintcheck/crates"]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "cargo-clippy"
|
name = "cargo-clippy"
|
||||||
test = false
|
test = false
|
||||||
|
@ -37,8 +40,8 @@ tempfile = { version = "3.1.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
cargo_metadata = "0.12"
|
cargo_metadata = "0.12"
|
||||||
compiletest_rs = { version = "0.5.0", features = ["tmp"] }
|
compiletest_rs = { version = "0.6.0", features = ["tmp"] }
|
||||||
tester = "0.7"
|
tester = "0.9"
|
||||||
clippy-mini-macro-test = { version = "0.2", path = "mini-macro" }
|
clippy-mini-macro-test = { version = "0.2", path = "mini-macro" }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
derive-new = "0.5"
|
derive-new = "0.5"
|
||||||
|
|
17
README.md
17
README.md
|
@ -98,6 +98,23 @@ If you want to run Clippy **only** on the given crate, use the `--no-deps` optio
|
||||||
cargo clippy -p example -- --no-deps
|
cargo clippy -p example -- --no-deps
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### As a rustc replacement (`clippy-driver`)
|
||||||
|
|
||||||
|
Clippy can also be used in projects that do not use cargo. To do so, you will need to replace
|
||||||
|
your `rustc` compilation commands with `clippy-driver`. For example, if your project runs:
|
||||||
|
|
||||||
|
```terminal
|
||||||
|
rustc --edition 2018 -Cpanic=abort foo.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, to enable Clippy, you will need to call:
|
||||||
|
|
||||||
|
```terminal
|
||||||
|
clippy-driver --edition 2018 -Cpanic=abort foo.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that `rustc` will still run, i.e. it will still emit the output files it normally does.
|
||||||
|
|
||||||
### Travis CI
|
### Travis CI
|
||||||
|
|
||||||
You can add Clippy to Travis CI in the same way you use it locally:
|
You can add Clippy to Travis CI in the same way you use it locally:
|
||||||
|
|
|
@ -19,8 +19,9 @@ shell-escape = "0.1"
|
||||||
tar = { version = "0.4.30", optional = true }
|
tar = { version = "0.4.30", optional = true }
|
||||||
toml = { version = "0.5", optional = true }
|
toml = { version = "0.5", optional = true }
|
||||||
ureq = { version = "2.0.0-rc3", optional = true }
|
ureq = { version = "2.0.0-rc3", optional = true }
|
||||||
|
rayon = { version = "1.5.0", optional = true }
|
||||||
walkdir = "2"
|
walkdir = "2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
lintcheck = ["flate2", "serde_json", "tar", "toml", "ureq", "serde", "fs_extra"]
|
lintcheck = ["flate2", "serde_json", "tar", "toml", "ureq", "serde", "fs_extra", "rayon"]
|
||||||
deny-warnings = []
|
deny-warnings = []
|
||||||
|
|
|
@ -1,28 +1,77 @@
|
||||||
# Clippy Dev Tool
|
# Clippy Dev Tool
|
||||||
|
|
||||||
The Clippy Dev Tool is a tool to ease Clippy development, similar to `rustc`s `x.py`.
|
The Clippy Dev Tool is a tool to ease Clippy development, similar to `rustc`s
|
||||||
|
`x.py`.
|
||||||
|
|
||||||
Functionalities (incomplete):
|
Functionalities (incomplete):
|
||||||
|
|
||||||
## `lintcheck`
|
## `lintcheck`
|
||||||
Runs clippy on a fixed set of crates read from `clippy_dev/lintcheck_crates.toml`
|
|
||||||
and saves logs of the lint warnings into the repo.
|
Runs clippy on a fixed set of crates read from
|
||||||
We can then check the diff and spot new or disappearing warnings.
|
`clippy_dev/lintcheck_crates.toml` and saves logs of the lint warnings into the
|
||||||
|
repo. We can then check the diff and spot new or disappearing warnings.
|
||||||
|
|
||||||
From the repo root, run:
|
From the repo root, run:
|
||||||
````
|
|
||||||
|
```
|
||||||
cargo run --target-dir clippy_dev/target --package clippy_dev \
|
cargo run --target-dir clippy_dev/target --package clippy_dev \
|
||||||
--bin clippy_dev --manifest-path clippy_dev/Cargo.toml --features lintcheck -- lintcheck
|
--bin clippy_dev --manifest-path clippy_dev/Cargo.toml --features lintcheck -- lintcheck
|
||||||
````
|
```
|
||||||
|
|
||||||
or
|
or
|
||||||
````
|
|
||||||
|
```
|
||||||
cargo dev-lintcheck
|
cargo dev-lintcheck
|
||||||
````
|
```
|
||||||
|
|
||||||
By default the logs will be saved into `lintcheck-logs/lintcheck_crates_logs.txt`.
|
By default the logs will be saved into
|
||||||
|
`lintcheck-logs/lintcheck_crates_logs.txt`.
|
||||||
|
|
||||||
You can set a custom sources.toml by adding `--crates-toml custom.toml`
|
You can set a custom sources.toml by adding `--crates-toml custom.toml` or using
|
||||||
where `custom.toml` must be a relative path from the repo root.
|
`LINTCHECK_TOML="custom.toml"` where `custom.toml` must be a relative path from
|
||||||
|
the repo root.
|
||||||
|
|
||||||
The results will then be saved to `lintcheck-logs/custom_logs.toml`.
|
The results will then be saved to `lintcheck-logs/custom_logs.toml`.
|
||||||
|
|
||||||
|
### Configuring the Crate Sources
|
||||||
|
|
||||||
|
The sources to check are saved in a `toml` file. There are three types of
|
||||||
|
sources.
|
||||||
|
|
||||||
|
1. Crates-io Source
|
||||||
|
|
||||||
|
```toml
|
||||||
|
bitflags = {name = "bitflags", versions = ['1.2.1']}
|
||||||
|
```
|
||||||
|
Requires a "name" and one or multiple "versions" to be checked.
|
||||||
|
|
||||||
|
2. `git` Source
|
||||||
|
````toml
|
||||||
|
puffin = {name = "puffin", git_url = "https://github.com/EmbarkStudios/puffin", git_hash = "02dd4a3"}
|
||||||
|
````
|
||||||
|
Requires a name, the url to the repo and unique identifier of a commit,
|
||||||
|
branch or tag which is checked out before linting. There is no way to always
|
||||||
|
check `HEAD` because that would lead to changing lint-results as the repo
|
||||||
|
would get updated. If `git_url` or `git_hash` is missing, an error will be
|
||||||
|
thrown.
|
||||||
|
|
||||||
|
3. Local Dependency
|
||||||
|
```toml
|
||||||
|
clippy = {name = "clippy", path = "/home/user/clippy"}
|
||||||
|
```
|
||||||
|
For when you want to add a repository that is not published yet.
|
||||||
|
|
||||||
|
#### Command Line Options (optional)
|
||||||
|
|
||||||
|
```toml
|
||||||
|
bitflags = {name = "bitflags", versions = ['1.2.1'], options = ['-Wclippy::pedantic', '-Wclippy::cargo']}
|
||||||
|
```
|
||||||
|
|
||||||
|
It is possible to specify command line options for each crate. This makes it
|
||||||
|
possible to only check a crate for certain lint groups. If no options are
|
||||||
|
specified, the lint groups `clippy::all`, `clippy::pedantic`, and
|
||||||
|
`clippy::cargo` are checked. If an empty array is specified only `clippy::all`
|
||||||
|
is checked.
|
||||||
|
|
||||||
|
**Note:** `-Wclippy::all` is always enabled by default, unless `-Aclippy::all`
|
||||||
|
is explicitly specified in the options.
|
||||||
|
|
|
@ -42,9 +42,10 @@ pub fn bless(ignore_timestamp: bool) {
|
||||||
.for_each(|f| {
|
.for_each(|f| {
|
||||||
let test_name = f.path().strip_prefix(test_suite_dir).unwrap();
|
let test_name = f.path().strip_prefix(test_suite_dir).unwrap();
|
||||||
for &ext in &["stdout", "stderr", "fixed"] {
|
for &ext in &["stdout", "stderr", "fixed"] {
|
||||||
|
let test_name_ext = format!("stage-id.{}", ext);
|
||||||
update_reference_file(
|
update_reference_file(
|
||||||
f.path().with_extension(ext),
|
f.path().with_extension(ext),
|
||||||
test_name.with_extension(ext),
|
test_name.with_extension(test_name_ext),
|
||||||
ignore_timestamp,
|
ignore_timestamp,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,20 +11,22 @@ use crate::clippy_project_root;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::{fmt, fs::write, path::PathBuf};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
use std::{env, fmt, fs::write, path::PathBuf};
|
||||||
|
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
|
use rayon::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
// use this to store the crates when interacting with the crates.toml file
|
/// List of sources to check, loaded from a .toml file
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
struct CrateList {
|
struct SourceList {
|
||||||
crates: HashMap<String, TomlCrate>,
|
crates: HashMap<String, TomlCrate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// crate data we stored in the toml, can have multiple versions per crate
|
/// A crate source stored inside the .toml
|
||||||
// A single TomlCrate is laster mapped to several CrateSources in that case
|
/// will be translated into on one of the `CrateSource` variants
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
struct TomlCrate {
|
struct TomlCrate {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -32,27 +34,42 @@ struct TomlCrate {
|
||||||
git_url: Option<String>,
|
git_url: Option<String>,
|
||||||
git_hash: Option<String>,
|
git_hash: Option<String>,
|
||||||
path: Option<String>,
|
path: Option<String>,
|
||||||
|
options: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// represents an archive we download from crates.io, or a git repo, or a local repo
|
/// Represents an archive we download from crates.io, or a git repo, or a local repo/folder
|
||||||
#[derive(Debug, Serialize, Deserialize, Eq, Hash, PartialEq)]
|
/// Once processed (downloaded/extracted/cloned/copied...), this will be translated into a `Crate`
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Eq, Hash, PartialEq, Ord, PartialOrd)]
|
||||||
enum CrateSource {
|
enum CrateSource {
|
||||||
CratesIo { name: String, version: String },
|
CratesIo {
|
||||||
Git { name: String, url: String, commit: String },
|
name: String,
|
||||||
Path { name: String, path: PathBuf },
|
version: String,
|
||||||
|
options: Option<Vec<String>>,
|
||||||
|
},
|
||||||
|
Git {
|
||||||
|
name: String,
|
||||||
|
url: String,
|
||||||
|
commit: String,
|
||||||
|
options: Option<Vec<String>>,
|
||||||
|
},
|
||||||
|
Path {
|
||||||
|
name: String,
|
||||||
|
path: PathBuf,
|
||||||
|
options: Option<Vec<String>>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// represents the extracted sourcecode of a crate
|
/// Represents the actual source code of a crate that we ran "cargo clippy" on
|
||||||
// we actually don't need to special-case git repos here because it does not matter for clippy, yay!
|
|
||||||
// (clippy only needs a simple path)
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Crate {
|
struct Crate {
|
||||||
version: String,
|
version: String,
|
||||||
name: String,
|
name: String,
|
||||||
// path to the extracted sources that clippy can check
|
// path to the extracted sources that clippy can check
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
options: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A single warning that clippy issued while checking a `Crate`
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ClippyWarning {
|
struct ClippyWarning {
|
||||||
crate_name: String,
|
crate_name: String,
|
||||||
|
@ -62,7 +79,7 @@ struct ClippyWarning {
|
||||||
column: String,
|
column: String,
|
||||||
linttype: String,
|
linttype: String,
|
||||||
message: String,
|
message: String,
|
||||||
ice: bool,
|
is_ice: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for ClippyWarning {
|
impl std::fmt::Display for ClippyWarning {
|
||||||
|
@ -76,9 +93,12 @@ impl std::fmt::Display for ClippyWarning {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CrateSource {
|
impl CrateSource {
|
||||||
|
/// Makes the sources available on the disk for clippy to check.
|
||||||
|
/// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or
|
||||||
|
/// copies a local folder
|
||||||
fn download_and_extract(&self) -> Crate {
|
fn download_and_extract(&self) -> Crate {
|
||||||
match self {
|
match self {
|
||||||
CrateSource::CratesIo { name, version } => {
|
CrateSource::CratesIo { name, version, options } => {
|
||||||
let extract_dir = PathBuf::from("target/lintcheck/crates");
|
let extract_dir = PathBuf::from("target/lintcheck/crates");
|
||||||
let krate_download_dir = PathBuf::from("target/lintcheck/downloads");
|
let krate_download_dir = PathBuf::from("target/lintcheck/downloads");
|
||||||
|
|
||||||
|
@ -110,9 +130,15 @@ impl CrateSource {
|
||||||
version: version.clone(),
|
version: version.clone(),
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
path: extract_dir.join(format!("{}-{}/", name, version)),
|
path: extract_dir.join(format!("{}-{}/", name, version)),
|
||||||
|
options: options.clone(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
CrateSource::Git { name, url, commit } => {
|
CrateSource::Git {
|
||||||
|
name,
|
||||||
|
url,
|
||||||
|
commit,
|
||||||
|
options,
|
||||||
|
} => {
|
||||||
let repo_path = {
|
let repo_path = {
|
||||||
let mut repo_path = PathBuf::from("target/lintcheck/crates");
|
let mut repo_path = PathBuf::from("target/lintcheck/crates");
|
||||||
// add a -git suffix in case we have the same crate from crates.io and a git repo
|
// add a -git suffix in case we have the same crate from crates.io and a git repo
|
||||||
|
@ -122,27 +148,37 @@ impl CrateSource {
|
||||||
// clone the repo if we have not done so
|
// clone the repo if we have not done so
|
||||||
if !repo_path.is_dir() {
|
if !repo_path.is_dir() {
|
||||||
println!("Cloning {} and checking out {}", url, commit);
|
println!("Cloning {} and checking out {}", url, commit);
|
||||||
Command::new("git")
|
if !Command::new("git")
|
||||||
.arg("clone")
|
.arg("clone")
|
||||||
.arg(url)
|
.arg(url)
|
||||||
.arg(&repo_path)
|
.arg(&repo_path)
|
||||||
.output()
|
.status()
|
||||||
.expect("Failed to clone git repo!");
|
.expect("Failed to clone git repo!")
|
||||||
|
.success()
|
||||||
|
{
|
||||||
|
eprintln!("Failed to clone {} into {}", url, repo_path.display())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// check out the commit/branch/whatever
|
// check out the commit/branch/whatever
|
||||||
Command::new("git")
|
if !Command::new("git")
|
||||||
.arg("checkout")
|
.arg("checkout")
|
||||||
.arg(commit)
|
.arg(commit)
|
||||||
.output()
|
.current_dir(&repo_path)
|
||||||
.expect("Failed to check out commit");
|
.status()
|
||||||
|
.expect("Failed to check out commit")
|
||||||
|
.success()
|
||||||
|
{
|
||||||
|
eprintln!("Failed to checkout {} of repo at {}", commit, repo_path.display())
|
||||||
|
}
|
||||||
|
|
||||||
Crate {
|
Crate {
|
||||||
version: commit.clone(),
|
version: commit.clone(),
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
path: repo_path,
|
path: repo_path,
|
||||||
|
options: options.clone(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
CrateSource::Path { name, path } => {
|
CrateSource::Path { name, path, options } => {
|
||||||
use fs_extra::dir;
|
use fs_extra::dir;
|
||||||
|
|
||||||
// simply copy the entire directory into our target dir
|
// simply copy the entire directory into our target dir
|
||||||
|
@ -171,6 +207,7 @@ impl CrateSource {
|
||||||
version: String::from("local"),
|
version: String::from("local"),
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
path: crate_root,
|
path: crate_root,
|
||||||
|
options: options.clone(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -178,24 +215,56 @@ impl CrateSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Crate {
|
impl Crate {
|
||||||
fn run_clippy_lints(&self, cargo_clippy_path: &PathBuf) -> Vec<ClippyWarning> {
|
/// Run `cargo clippy` on the `Crate` and collect and return all the lint warnings that clippy
|
||||||
println!("Linting {} {}...", &self.name, &self.version);
|
/// issued
|
||||||
|
fn run_clippy_lints(
|
||||||
|
&self,
|
||||||
|
cargo_clippy_path: &PathBuf,
|
||||||
|
target_dir_index: &AtomicUsize,
|
||||||
|
thread_limit: usize,
|
||||||
|
total_crates_to_lint: usize,
|
||||||
|
) -> Vec<ClippyWarning> {
|
||||||
|
// advance the atomic index by one
|
||||||
|
let index = target_dir_index.fetch_add(1, Ordering::SeqCst);
|
||||||
|
// "loop" the index within 0..thread_limit
|
||||||
|
let target_dir_index = index % thread_limit;
|
||||||
|
let perc = ((index * 100) as f32 / total_crates_to_lint as f32) as u8;
|
||||||
|
|
||||||
|
if thread_limit == 1 {
|
||||||
|
println!(
|
||||||
|
"{}/{} {}% Linting {} {}",
|
||||||
|
index, total_crates_to_lint, perc, &self.name, &self.version
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
"{}/{} {}% Linting {} {} in target dir {:?}",
|
||||||
|
index, total_crates_to_lint, perc, &self.name, &self.version, target_dir_index
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let cargo_clippy_path = std::fs::canonicalize(cargo_clippy_path).unwrap();
|
let cargo_clippy_path = std::fs::canonicalize(cargo_clippy_path).unwrap();
|
||||||
|
|
||||||
let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir/");
|
let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir");
|
||||||
|
|
||||||
|
let mut args = vec!["--", "--message-format=json", "--", "--cap-lints=warn"];
|
||||||
|
|
||||||
|
if let Some(options) = &self.options {
|
||||||
|
for opt in options {
|
||||||
|
args.push(opt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args.extend(&["-Wclippy::pedantic", "-Wclippy::cargo"])
|
||||||
|
}
|
||||||
|
|
||||||
let all_output = std::process::Command::new(&cargo_clippy_path)
|
let all_output = std::process::Command::new(&cargo_clippy_path)
|
||||||
.env("CARGO_TARGET_DIR", shared_target_dir)
|
// use the looping index to create individual target dirs
|
||||||
|
.env(
|
||||||
|
"CARGO_TARGET_DIR",
|
||||||
|
shared_target_dir.join(format!("_{:?}", target_dir_index)),
|
||||||
|
)
|
||||||
// lint warnings will look like this:
|
// lint warnings will look like this:
|
||||||
// src/cargo/ops/cargo_compile.rs:127:35: warning: usage of `FromIterator::from_iter`
|
// src/cargo/ops/cargo_compile.rs:127:35: warning: usage of `FromIterator::from_iter`
|
||||||
.args(&[
|
.args(&args)
|
||||||
"--",
|
|
||||||
"--message-format=json",
|
|
||||||
"--",
|
|
||||||
"--cap-lints=warn",
|
|
||||||
"-Wclippy::pedantic",
|
|
||||||
"-Wclippy::cargo",
|
|
||||||
])
|
|
||||||
.current_dir(&self.path)
|
.current_dir(&self.path)
|
||||||
.output()
|
.output()
|
||||||
.unwrap_or_else(|error| {
|
.unwrap_or_else(|error| {
|
||||||
|
@ -211,28 +280,69 @@ impl Crate {
|
||||||
let warnings: Vec<ClippyWarning> = output_lines
|
let warnings: Vec<ClippyWarning> = output_lines
|
||||||
.into_iter()
|
.into_iter()
|
||||||
// get all clippy warnings and ICEs
|
// get all clippy warnings and ICEs
|
||||||
.filter(|line| line.contains("clippy::") || line.contains("internal compiler error: "))
|
.filter(|line| filter_clippy_warnings(&line))
|
||||||
.map(|json_msg| parse_json_message(json_msg, &self))
|
.map(|json_msg| parse_json_message(json_msg, &self))
|
||||||
.collect();
|
.collect();
|
||||||
warnings
|
warnings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_clippy() {
|
/// takes a single json-formatted clippy warnings and returns true (we are interested in that line)
|
||||||
Command::new("cargo")
|
/// or false (we aren't)
|
||||||
.arg("build")
|
fn filter_clippy_warnings(line: &str) -> bool {
|
||||||
.output()
|
// we want to collect ICEs because clippy might have crashed.
|
||||||
.expect("Failed to build clippy!");
|
// these are summarized later
|
||||||
|
if line.contains("internal compiler error: ") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// in general, we want all clippy warnings
|
||||||
|
// however due to some kind of bug, sometimes there are absolute paths
|
||||||
|
// to libcore files inside the message
|
||||||
|
// or we end up with cargo-metadata output (https://github.com/rust-lang/rust-clippy/issues/6508)
|
||||||
|
|
||||||
|
// filter out these message to avoid unnecessary noise in the logs
|
||||||
|
if line.contains("clippy::")
|
||||||
|
&& !(line.contains("could not read cargo metadata")
|
||||||
|
|| (line.contains(".rustup") && line.contains("toolchains")))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a list of CrateSources we want to check from a "lintcheck_crates.toml" file.
|
/// get the path to lintchecks crate sources .toml file, check LINTCHECK_TOML first but if it's
|
||||||
|
/// empty use the default path
|
||||||
|
fn lintcheck_config_toml(toml_path: Option<&str>) -> PathBuf {
|
||||||
|
PathBuf::from(
|
||||||
|
env::var("LINTCHECK_TOML").unwrap_or(
|
||||||
|
toml_path
|
||||||
|
.clone()
|
||||||
|
.unwrap_or("clippy_dev/lintcheck_crates.toml")
|
||||||
|
.to_string(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds clippy inside the repo to make sure we have a clippy executable we can use.
|
||||||
|
fn build_clippy() {
|
||||||
|
let status = Command::new("cargo")
|
||||||
|
.arg("build")
|
||||||
|
.status()
|
||||||
|
.expect("Failed to build clippy!");
|
||||||
|
if !status.success() {
|
||||||
|
eprintln!("Error: Failed to compile Clippy!");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a `toml` file and return a list of `CrateSources` that we want to check with clippy
|
||||||
fn read_crates(toml_path: Option<&str>) -> (String, Vec<CrateSource>) {
|
fn read_crates(toml_path: Option<&str>) -> (String, Vec<CrateSource>) {
|
||||||
let toml_path = PathBuf::from(toml_path.unwrap_or("clippy_dev/lintcheck_crates.toml"));
|
let toml_path = lintcheck_config_toml(toml_path);
|
||||||
// save it so that we can use the name of the sources.toml as name for the logfile later.
|
// save it so that we can use the name of the sources.toml as name for the logfile later.
|
||||||
let toml_filename = toml_path.file_stem().unwrap().to_str().unwrap().to_string();
|
let toml_filename = toml_path.file_stem().unwrap().to_str().unwrap().to_string();
|
||||||
let toml_content: String =
|
let toml_content: String =
|
||||||
std::fs::read_to_string(&toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display()));
|
std::fs::read_to_string(&toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display()));
|
||||||
let crate_list: CrateList =
|
let crate_list: SourceList =
|
||||||
toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{}", toml_path.display(), e));
|
toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{}", toml_path.display(), e));
|
||||||
// parse the hashmap of the toml file into a list of crates
|
// parse the hashmap of the toml file into a list of crates
|
||||||
let tomlcrates: Vec<TomlCrate> = crate_list
|
let tomlcrates: Vec<TomlCrate> = crate_list
|
||||||
|
@ -249,6 +359,7 @@ fn read_crates(toml_path: Option<&str>) -> (String, Vec<CrateSource>) {
|
||||||
crate_sources.push(CrateSource::Path {
|
crate_sources.push(CrateSource::Path {
|
||||||
name: tk.name.clone(),
|
name: tk.name.clone(),
|
||||||
path: PathBuf::from(path),
|
path: PathBuf::from(path),
|
||||||
|
options: tk.options.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,6 +369,7 @@ fn read_crates(toml_path: Option<&str>) -> (String, Vec<CrateSource>) {
|
||||||
crate_sources.push(CrateSource::CratesIo {
|
crate_sources.push(CrateSource::CratesIo {
|
||||||
name: tk.name.clone(),
|
name: tk.name.clone(),
|
||||||
version: ver.to_string(),
|
version: ver.to_string(),
|
||||||
|
options: tk.options.clone(),
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -267,6 +379,7 @@ fn read_crates(toml_path: Option<&str>) -> (String, Vec<CrateSource>) {
|
||||||
name: tk.name.clone(),
|
name: tk.name.clone(),
|
||||||
url: tk.git_url.clone().unwrap(),
|
url: tk.git_url.clone().unwrap(),
|
||||||
commit: tk.git_hash.clone().unwrap(),
|
commit: tk.git_hash.clone().unwrap(),
|
||||||
|
options: tk.options.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// if we have a version as well as a git data OR only one git data, something is funky
|
// if we have a version as well as a git data OR only one git data, something is funky
|
||||||
|
@ -283,10 +396,13 @@ fn read_crates(toml_path: Option<&str>) -> (String, Vec<CrateSource>) {
|
||||||
unreachable!("Failed to translate TomlCrate into CrateSource!");
|
unreachable!("Failed to translate TomlCrate into CrateSource!");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// sort the crates
|
||||||
|
crate_sources.sort();
|
||||||
|
|
||||||
(toml_filename, crate_sources)
|
(toml_filename, crate_sources)
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract interesting data from a json lint message
|
/// Parse the json output of clippy and return a `ClippyWarning`
|
||||||
fn parse_json_message(json_message: &str, krate: &Crate) -> ClippyWarning {
|
fn parse_json_message(json_message: &str, krate: &Crate) -> ClippyWarning {
|
||||||
let jmsg: Value = serde_json::from_str(&json_message).unwrap_or_else(|e| panic!("Failed to parse json:\n{:?}", e));
|
let jmsg: Value = serde_json::from_str(&json_message).unwrap_or_else(|e| panic!("Failed to parse json:\n{:?}", e));
|
||||||
|
|
||||||
|
@ -307,18 +423,84 @@ fn parse_json_message(json_message: &str, krate: &Crate) -> ClippyWarning {
|
||||||
.into(),
|
.into(),
|
||||||
linttype: jmsg["message"]["code"]["code"].to_string().trim_matches('"').into(),
|
linttype: jmsg["message"]["code"]["code"].to_string().trim_matches('"').into(),
|
||||||
message: jmsg["message"]["message"].to_string().trim_matches('"').into(),
|
message: jmsg["message"]["message"].to_string().trim_matches('"').into(),
|
||||||
ice: json_message.contains("internal compiler error: "),
|
is_ice: json_message.contains("internal compiler error: "),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// the main fn
|
/// Generate a short list of occuring lints-types and their count
|
||||||
pub fn run(clap_config: &ArgMatches) {
|
fn gather_stats(clippy_warnings: &[ClippyWarning]) -> String {
|
||||||
let cargo_clippy_path: PathBuf = PathBuf::from("target/debug/cargo-clippy");
|
// count lint type occurrences
|
||||||
|
let mut counter: HashMap<&String, usize> = HashMap::new();
|
||||||
|
clippy_warnings
|
||||||
|
.iter()
|
||||||
|
.for_each(|wrn| *counter.entry(&wrn.linttype).or_insert(0) += 1);
|
||||||
|
|
||||||
|
// collect into a tupled list for sorting
|
||||||
|
let mut stats: Vec<(&&String, &usize)> = counter.iter().map(|(lint, count)| (lint, count)).collect();
|
||||||
|
// sort by "000{count} {clippy::lintname}"
|
||||||
|
// to not have a lint with 200 and 2 warnings take the same spot
|
||||||
|
stats.sort_by_key(|(lint, count)| format!("{:0>4}, {}", count, lint));
|
||||||
|
|
||||||
|
stats
|
||||||
|
.iter()
|
||||||
|
.map(|(lint, count)| format!("{} {}\n", lint, count))
|
||||||
|
.collect::<String>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// check if the latest modification of the logfile is older than the modification date of the
|
||||||
|
/// clippy binary, if this is true, we should clean the lintchec shared target directory and recheck
|
||||||
|
fn lintcheck_needs_rerun(toml_path: Option<&str>) -> bool {
|
||||||
|
let clippy_modified: std::time::SystemTime = {
|
||||||
|
let mut times = ["target/debug/clippy-driver", "target/debug/cargo-clippy"]
|
||||||
|
.iter()
|
||||||
|
.map(|p| {
|
||||||
|
std::fs::metadata(p)
|
||||||
|
.expect("failed to get metadata of file")
|
||||||
|
.modified()
|
||||||
|
.expect("failed to get modification date")
|
||||||
|
});
|
||||||
|
// the lates modification of either of the binaries
|
||||||
|
std::cmp::max(times.next().unwrap(), times.next().unwrap())
|
||||||
|
};
|
||||||
|
|
||||||
|
let logs_modified: std::time::SystemTime = std::fs::metadata(lintcheck_config_toml(toml_path))
|
||||||
|
.expect("failed to get metadata of file")
|
||||||
|
.modified()
|
||||||
|
.expect("failed to get modification date");
|
||||||
|
|
||||||
|
// if clippys modification time is bigger (older) than the logs mod time, we need to rerun lintcheck
|
||||||
|
clippy_modified > logs_modified
|
||||||
|
}
|
||||||
|
|
||||||
|
/// lintchecks `main()` function
|
||||||
|
pub fn run(clap_config: &ArgMatches) {
|
||||||
println!("Compiling clippy...");
|
println!("Compiling clippy...");
|
||||||
build_clippy();
|
build_clippy();
|
||||||
println!("Done compiling");
|
println!("Done compiling");
|
||||||
|
|
||||||
|
let clap_toml_path = clap_config.value_of("crates-toml");
|
||||||
|
|
||||||
|
// if the clippy bin is newer than our logs, throw away target dirs to force clippy to
|
||||||
|
// refresh the logs
|
||||||
|
if lintcheck_needs_rerun(clap_toml_path) {
|
||||||
|
let shared_target_dir = "target/lintcheck/shared_target_dir";
|
||||||
|
match std::fs::metadata(&shared_target_dir) {
|
||||||
|
Ok(metadata) => {
|
||||||
|
if metadata.is_dir() {
|
||||||
|
println!("Clippy is newer than lint check logs, clearing lintcheck shared target dir...");
|
||||||
|
std::fs::remove_dir_all(&shared_target_dir)
|
||||||
|
.expect("failed to remove target/lintcheck/shared_target_dir");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => { // dir probably does not exist, don't remove anything
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let cargo_clippy_path: PathBuf = PathBuf::from("target/debug/cargo-clippy")
|
||||||
|
.canonicalize()
|
||||||
|
.expect("failed to canonicalize path to clippy binary");
|
||||||
|
|
||||||
// assert that clippy is found
|
// assert that clippy is found
|
||||||
assert!(
|
assert!(
|
||||||
cargo_clippy_path.is_file(),
|
cargo_clippy_path.is_file(),
|
||||||
|
@ -335,7 +517,7 @@ pub fn run(clap_config: &ArgMatches) {
|
||||||
// download and extract the crates, then run clippy on them and collect clippys warnings
|
// download and extract the crates, then run clippy on them and collect clippys warnings
|
||||||
// flatten into one big list of warnings
|
// flatten into one big list of warnings
|
||||||
|
|
||||||
let (filename, crates) = read_crates(clap_config.value_of("crates-toml"));
|
let (filename, crates) = read_crates(clap_toml_path);
|
||||||
|
|
||||||
let clippy_warnings: Vec<ClippyWarning> = if let Some(only_one_crate) = clap_config.value_of("only") {
|
let clippy_warnings: Vec<ClippyWarning> = if let Some(only_one_crate) = clap_config.value_of("only") {
|
||||||
// if we don't have the specified crate in the .toml, throw an error
|
// if we don't have the specified crate in the .toml, throw an error
|
||||||
|
@ -359,45 +541,60 @@ pub fn run(clap_config: &ArgMatches) {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|krate| krate.download_and_extract())
|
.map(|krate| krate.download_and_extract())
|
||||||
.filter(|krate| krate.name == only_one_crate)
|
.filter(|krate| krate.name == only_one_crate)
|
||||||
.map(|krate| krate.run_clippy_lints(&cargo_clippy_path))
|
.map(|krate| krate.run_clippy_lints(&cargo_clippy_path, &AtomicUsize::new(0), 1, 1))
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
|
let counter = std::sync::atomic::AtomicUsize::new(0);
|
||||||
|
|
||||||
|
// Ask rayon for thread count. Assume that half of that is the number of physical cores
|
||||||
|
// Use one target dir for each core so that we can run N clippys in parallel.
|
||||||
|
// We need to use different target dirs because cargo would lock them for a single build otherwise,
|
||||||
|
// killing the parallelism. However this also means that deps will only be reused half/a
|
||||||
|
// quarter of the time which might result in a longer wall clock runtime
|
||||||
|
|
||||||
|
// This helps when we check many small crates with dep-trees that don't have a lot of branches in
|
||||||
|
// order to achive some kind of parallelism
|
||||||
|
|
||||||
|
// by default, use a single thread
|
||||||
|
let num_cpus = match clap_config.value_of("threads") {
|
||||||
|
Some(threads) => {
|
||||||
|
let threads: usize = threads
|
||||||
|
.parse()
|
||||||
|
.expect(&format!("Failed to parse '{}' to a digit", threads));
|
||||||
|
if threads == 0 {
|
||||||
|
// automatic choice
|
||||||
|
// Rayon seems to return thread count so half that for core count
|
||||||
|
(rayon::current_num_threads() / 2) as usize
|
||||||
|
} else {
|
||||||
|
threads
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// no -j passed, use a single thread
|
||||||
|
None => 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let num_crates = crates.len();
|
||||||
|
|
||||||
// check all crates (default)
|
// check all crates (default)
|
||||||
crates
|
crates
|
||||||
.into_iter()
|
.into_par_iter()
|
||||||
.map(|krate| krate.download_and_extract())
|
.map(|krate| krate.download_and_extract())
|
||||||
.map(|krate| krate.run_clippy_lints(&cargo_clippy_path))
|
.map(|krate| krate.run_clippy_lints(&cargo_clippy_path, &counter, num_cpus, num_crates))
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
// generate some stats:
|
// generate some stats
|
||||||
|
let stats_formatted = gather_stats(&clippy_warnings);
|
||||||
|
|
||||||
// grab crashes/ICEs, save the crate name and the ice message
|
// grab crashes/ICEs, save the crate name and the ice message
|
||||||
let ices: Vec<(&String, &String)> = clippy_warnings
|
let ices: Vec<(&String, &String)> = clippy_warnings
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|warning| warning.ice)
|
.filter(|warning| warning.is_ice)
|
||||||
.map(|w| (&w.crate_name, &w.message))
|
.map(|w| (&w.crate_name, &w.message))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// count lint type occurrences
|
|
||||||
let mut counter: HashMap<&String, usize> = HashMap::new();
|
|
||||||
clippy_warnings
|
|
||||||
.iter()
|
|
||||||
.for_each(|wrn| *counter.entry(&wrn.linttype).or_insert(0) += 1);
|
|
||||||
|
|
||||||
// collect into a tupled list for sorting
|
|
||||||
let mut stats: Vec<(&&String, &usize)> = counter.iter().map(|(lint, count)| (lint, count)).collect();
|
|
||||||
// sort by "000{count} {clippy::lintname}"
|
|
||||||
// to not have a lint with 200 and 2 warnings take the same spot
|
|
||||||
stats.sort_by_key(|(lint, count)| format!("{:0>4}, {}", count, lint));
|
|
||||||
|
|
||||||
let stats_formatted: String = stats
|
|
||||||
.iter()
|
|
||||||
.map(|(lint, count)| format!("{} {}\n", lint, count))
|
|
||||||
.collect::<String>();
|
|
||||||
|
|
||||||
let mut all_msgs: Vec<String> = clippy_warnings.iter().map(|warning| warning.to_string()).collect();
|
let mut all_msgs: Vec<String> = clippy_warnings.iter().map(|warning| warning.to_string()).collect();
|
||||||
all_msgs.sort();
|
all_msgs.sort();
|
||||||
all_msgs.push("\n\n\n\nStats\n\n".into());
|
all_msgs.push("\n\n\n\nStats\n\n".into());
|
||||||
|
@ -411,5 +608,6 @@ pub fn run(clap_config: &ArgMatches) {
|
||||||
.for_each(|(cratename, msg)| text.push_str(&format!("{}: '{}'", cratename, msg)));
|
.for_each(|(cratename, msg)| text.push_str(&format!("{}: '{}'", cratename, msg)));
|
||||||
|
|
||||||
let file = format!("lintcheck-logs/{}_logs.txt", filename);
|
let file = format!("lintcheck-logs/{}_logs.txt", filename);
|
||||||
|
println!("Writing logs to {}", file);
|
||||||
write(file, text).unwrap();
|
write(file, text).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,14 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
|
||||||
.value_name("CRATES-SOURCES-TOML-PATH")
|
.value_name("CRATES-SOURCES-TOML-PATH")
|
||||||
.long("crates-toml")
|
.long("crates-toml")
|
||||||
.help("set the path for a crates.toml where lintcheck should read the sources from"),
|
.help("set the path for a crates.toml where lintcheck should read the sources from"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("threads")
|
||||||
|
.takes_value(true)
|
||||||
|
.value_name("N")
|
||||||
|
.short("j")
|
||||||
|
.long("jobs")
|
||||||
|
.help("number of threads to use, 0 automatic choice"),
|
||||||
);
|
);
|
||||||
|
|
||||||
let app = App::new("Clippy developer tooling")
|
let app = App::new("Clippy developer tooling")
|
||||||
|
|
|
@ -18,6 +18,7 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cargo_metadata = "0.12"
|
cargo_metadata = "0.12"
|
||||||
|
clippy_utils = { path = "../clippy_utils" }
|
||||||
if_chain = "1.0.0"
|
if_chain = "1.0.0"
|
||||||
itertools = "0.9"
|
itertools = "0.9"
|
||||||
pulldown-cmark = { version = "0.8", default-features = false }
|
pulldown-cmark = { version = "0.8", default-features = false }
|
||||||
|
@ -38,4 +39,4 @@ syn = { version = "1", features = ["full"] }
|
||||||
[features]
|
[features]
|
||||||
deny-warnings = []
|
deny-warnings = []
|
||||||
# build clippy with internal lints enabled, off by default
|
# build clippy with internal lints enabled, off by default
|
||||||
internal-lints = []
|
internal-lints = ["clippy_utils/internal-lints"]
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
use crate::utils::{differing_macro_contexts, snippet_block_with_applicability, span_lint, span_lint_and_sugg};
|
use crate::utils::{
|
||||||
|
differing_macro_contexts, get_parent_expr, get_trait_def_id, implements_trait, paths,
|
||||||
|
snippet_block_with_applicability, span_lint, span_lint_and_sugg,
|
||||||
|
};
|
||||||
|
use if_chain::if_chain;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
||||||
use rustc_hir::{BlockCheckMode, Expr, ExprKind};
|
use rustc_hir::{BlockCheckMode, Expr, ExprKind};
|
||||||
|
@ -52,6 +56,18 @@ impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
|
||||||
|
|
||||||
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
|
||||||
if let ExprKind::Closure(_, _, eid, _, _) = expr.kind {
|
if let ExprKind::Closure(_, _, eid, _, _) = expr.kind {
|
||||||
|
// do not lint if the closure is called using an iterator (see #1141)
|
||||||
|
if_chain! {
|
||||||
|
if let Some(parent) = get_parent_expr(self.cx, expr);
|
||||||
|
if let ExprKind::MethodCall(_, _, args, _) = parent.kind;
|
||||||
|
let caller = self.cx.typeck_results().expr_ty(&args[0]);
|
||||||
|
if let Some(iter_id) = get_trait_def_id(self.cx, &paths::ITERATOR);
|
||||||
|
if implements_trait(self.cx, caller, iter_id, &[]);
|
||||||
|
then {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let body = self.cx.tcx.hir().body(eid);
|
let body = self.cx.tcx.hir().body(eid);
|
||||||
let ex = &body.value;
|
let ex = &body.value;
|
||||||
if matches!(ex.kind, ExprKind::Block(_, _)) && !body.value.span.from_expansion() {
|
if matches!(ex.kind, ExprKind::Block(_, _)) && !body.value.span.from_expansion() {
|
||||||
|
|
|
@ -122,6 +122,7 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) {
|
||||||
if let ast::ExprKind::Block(ref block, _) = else_.kind;
|
if let ast::ExprKind::Block(ref block, _) = else_.kind;
|
||||||
if !block_starts_with_comment(cx, block);
|
if !block_starts_with_comment(cx, block);
|
||||||
if let Some(else_) = expr_block(block);
|
if let Some(else_) = expr_block(block);
|
||||||
|
if else_.attrs.is_empty();
|
||||||
if !else_.span.from_expansion();
|
if !else_.span.from_expansion();
|
||||||
if let ast::ExprKind::If(..) = else_.kind;
|
if let ast::ExprKind::If(..) = else_.kind;
|
||||||
then {
|
then {
|
||||||
|
@ -143,16 +144,12 @@ fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if !block_starts_with_comment(cx, then);
|
if !block_starts_with_comment(cx, then);
|
||||||
if let Some(inner) = expr_block(then);
|
if let Some(inner) = expr_block(then);
|
||||||
|
if inner.attrs.is_empty();
|
||||||
if let ast::ExprKind::If(ref check_inner, ref content, None) = inner.kind;
|
if let ast::ExprKind::If(ref check_inner, ref content, None) = inner.kind;
|
||||||
|
// Prevent triggering on `if c { if let a = b { .. } }`.
|
||||||
|
if !matches!(check_inner.kind, ast::ExprKind::Let(..));
|
||||||
|
if expr.span.ctxt() == inner.span.ctxt();
|
||||||
then {
|
then {
|
||||||
if let ast::ExprKind::Let(..) = check_inner.kind {
|
|
||||||
// Prevent triggering on `if c { if let a = b { .. } }`.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if expr.span.ctxt() != inner.span.ctxt() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
span_lint_and_then(cx, COLLAPSIBLE_IF, expr.span, "this `if` statement can be collapsed", |diag| {
|
span_lint_and_then(cx, COLLAPSIBLE_IF, expr.span, "this `if` statement can be collapsed", |diag| {
|
||||||
let lhs = Sugg::ast(cx, check, "..");
|
let lhs = Sugg::ast(cx, check, "..");
|
||||||
let rhs = Sugg::ast(cx, check_inner, "..");
|
let rhs = Sugg::ast(cx, check_inner, "..");
|
||||||
|
|
|
@ -96,12 +96,12 @@ fn check_arm<'tcx>(arm: &Arm<'tcx>, wild_outer_arm: &Arm<'tcx>, cx: &LateContext
|
||||||
cx,
|
cx,
|
||||||
COLLAPSIBLE_MATCH,
|
COLLAPSIBLE_MATCH,
|
||||||
expr.span,
|
expr.span,
|
||||||
"Unnecessary nested match",
|
"unnecessary nested match",
|
||||||
|diag| {
|
|diag| {
|
||||||
let mut help_span = MultiSpan::from_spans(vec![binding_span, non_wild_inner_arm.pat.span]);
|
let mut help_span = MultiSpan::from_spans(vec![binding_span, non_wild_inner_arm.pat.span]);
|
||||||
help_span.push_span_label(binding_span, "Replace this binding".into());
|
help_span.push_span_label(binding_span, "replace this binding".into());
|
||||||
help_span.push_span_label(non_wild_inner_arm.pat.span, "with this pattern".into());
|
help_span.push_span_label(non_wild_inner_arm.pat.span, "with this pattern".into());
|
||||||
diag.span_help(help_span, "The outer pattern can be modified to include the inner pattern.");
|
diag.span_help(help_span, "the outer pattern can be modified to include the inner pattern");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,574 +1 @@
|
||||||
#![allow(clippy::float_cmp)]
|
pub use clippy_utils::consts::*;
|
||||||
|
|
||||||
use crate::utils::{clip, sext, unsext};
|
|
||||||
use if_chain::if_chain;
|
|
||||||
use rustc_ast::ast::{self, LitFloatType, LitKind};
|
|
||||||
use rustc_data_structures::sync::Lrc;
|
|
||||||
use rustc_hir::def::{DefKind, Res};
|
|
||||||
use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, QPath, UnOp};
|
|
||||||
use rustc_lint::LateContext;
|
|
||||||
use rustc_middle::mir::interpret::Scalar;
|
|
||||||
use rustc_middle::ty::subst::{Subst, SubstsRef};
|
|
||||||
use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty, TyCtxt};
|
|
||||||
use rustc_middle::{bug, span_bug};
|
|
||||||
use rustc_span::symbol::Symbol;
|
|
||||||
use std::cmp::Ordering::{self, Equal};
|
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::hash::{Hash, Hasher};
|
|
||||||
|
|
||||||
/// A `LitKind`-like enum to fold constant `Expr`s into.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum Constant {
|
|
||||||
/// A `String` (e.g., "abc").
|
|
||||||
Str(String),
|
|
||||||
/// A binary string (e.g., `b"abc"`).
|
|
||||||
Binary(Lrc<[u8]>),
|
|
||||||
/// A single `char` (e.g., `'a'`).
|
|
||||||
Char(char),
|
|
||||||
/// An integer's bit representation.
|
|
||||||
Int(u128),
|
|
||||||
/// An `f32`.
|
|
||||||
F32(f32),
|
|
||||||
/// An `f64`.
|
|
||||||
F64(f64),
|
|
||||||
/// `true` or `false`.
|
|
||||||
Bool(bool),
|
|
||||||
/// An array of constants.
|
|
||||||
Vec(Vec<Constant>),
|
|
||||||
/// Also an array, but with only one constant, repeated N times.
|
|
||||||
Repeat(Box<Constant>, u64),
|
|
||||||
/// A tuple of constants.
|
|
||||||
Tuple(Vec<Constant>),
|
|
||||||
/// A raw pointer.
|
|
||||||
RawPtr(u128),
|
|
||||||
/// A reference
|
|
||||||
Ref(Box<Constant>),
|
|
||||||
/// A literal with syntax error.
|
|
||||||
Err(Symbol),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Constant {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
match (self, other) {
|
|
||||||
(&Self::Str(ref ls), &Self::Str(ref rs)) => ls == rs,
|
|
||||||
(&Self::Binary(ref l), &Self::Binary(ref r)) => l == r,
|
|
||||||
(&Self::Char(l), &Self::Char(r)) => l == r,
|
|
||||||
(&Self::Int(l), &Self::Int(r)) => l == r,
|
|
||||||
(&Self::F64(l), &Self::F64(r)) => {
|
|
||||||
// We want `Fw32 == FwAny` and `FwAny == Fw64`, and by transitivity we must have
|
|
||||||
// `Fw32 == Fw64`, so don’t compare them.
|
|
||||||
// `to_bits` is required to catch non-matching 0.0, -0.0, and NaNs.
|
|
||||||
l.to_bits() == r.to_bits()
|
|
||||||
},
|
|
||||||
(&Self::F32(l), &Self::F32(r)) => {
|
|
||||||
// We want `Fw32 == FwAny` and `FwAny == Fw64`, and by transitivity we must have
|
|
||||||
// `Fw32 == Fw64`, so don’t compare them.
|
|
||||||
// `to_bits` is required to catch non-matching 0.0, -0.0, and NaNs.
|
|
||||||
f64::from(l).to_bits() == f64::from(r).to_bits()
|
|
||||||
},
|
|
||||||
(&Self::Bool(l), &Self::Bool(r)) => l == r,
|
|
||||||
(&Self::Vec(ref l), &Self::Vec(ref r)) | (&Self::Tuple(ref l), &Self::Tuple(ref r)) => l == r,
|
|
||||||
(&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => ls == rs && lv == rv,
|
|
||||||
(&Self::Ref(ref lb), &Self::Ref(ref rb)) => *lb == *rb,
|
|
||||||
// TODO: are there inter-type equalities?
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hash for Constant {
|
|
||||||
fn hash<H>(&self, state: &mut H)
|
|
||||||
where
|
|
||||||
H: Hasher,
|
|
||||||
{
|
|
||||||
std::mem::discriminant(self).hash(state);
|
|
||||||
match *self {
|
|
||||||
Self::Str(ref s) => {
|
|
||||||
s.hash(state);
|
|
||||||
},
|
|
||||||
Self::Binary(ref b) => {
|
|
||||||
b.hash(state);
|
|
||||||
},
|
|
||||||
Self::Char(c) => {
|
|
||||||
c.hash(state);
|
|
||||||
},
|
|
||||||
Self::Int(i) => {
|
|
||||||
i.hash(state);
|
|
||||||
},
|
|
||||||
Self::F32(f) => {
|
|
||||||
f64::from(f).to_bits().hash(state);
|
|
||||||
},
|
|
||||||
Self::F64(f) => {
|
|
||||||
f.to_bits().hash(state);
|
|
||||||
},
|
|
||||||
Self::Bool(b) => {
|
|
||||||
b.hash(state);
|
|
||||||
},
|
|
||||||
Self::Vec(ref v) | Self::Tuple(ref v) => {
|
|
||||||
v.hash(state);
|
|
||||||
},
|
|
||||||
Self::Repeat(ref c, l) => {
|
|
||||||
c.hash(state);
|
|
||||||
l.hash(state);
|
|
||||||
},
|
|
||||||
Self::RawPtr(u) => {
|
|
||||||
u.hash(state);
|
|
||||||
},
|
|
||||||
Self::Ref(ref r) => {
|
|
||||||
r.hash(state);
|
|
||||||
},
|
|
||||||
Self::Err(ref s) => {
|
|
||||||
s.hash(state);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Constant {
|
|
||||||
pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option<Ordering> {
|
|
||||||
match (left, right) {
|
|
||||||
(&Self::Str(ref ls), &Self::Str(ref rs)) => Some(ls.cmp(rs)),
|
|
||||||
(&Self::Char(ref l), &Self::Char(ref r)) => Some(l.cmp(r)),
|
|
||||||
(&Self::Int(l), &Self::Int(r)) => {
|
|
||||||
if let ty::Int(int_ty) = *cmp_type.kind() {
|
|
||||||
Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty)))
|
|
||||||
} else {
|
|
||||||
Some(l.cmp(&r))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(&Self::F64(l), &Self::F64(r)) => l.partial_cmp(&r),
|
|
||||||
(&Self::F32(l), &Self::F32(r)) => l.partial_cmp(&r),
|
|
||||||
(&Self::Bool(ref l), &Self::Bool(ref r)) => Some(l.cmp(r)),
|
|
||||||
(&Self::Tuple(ref l), &Self::Tuple(ref r)) | (&Self::Vec(ref l), &Self::Vec(ref r)) => l
|
|
||||||
.iter()
|
|
||||||
.zip(r.iter())
|
|
||||||
.map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri))
|
|
||||||
.find(|r| r.map_or(true, |o| o != Ordering::Equal))
|
|
||||||
.unwrap_or_else(|| Some(l.len().cmp(&r.len()))),
|
|
||||||
(&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => {
|
|
||||||
match Self::partial_cmp(tcx, cmp_type, lv, rv) {
|
|
||||||
Some(Equal) => Some(ls.cmp(rs)),
|
|
||||||
x => x,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(&Self::Ref(ref lb), &Self::Ref(ref rb)) => Self::partial_cmp(tcx, cmp_type, lb, rb),
|
|
||||||
// TODO: are there any useful inter-type orderings?
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses a `LitKind` to a `Constant`.
|
|
||||||
pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
|
|
||||||
match *lit {
|
|
||||||
LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
|
|
||||||
LitKind::Byte(b) => Constant::Int(u128::from(b)),
|
|
||||||
LitKind::ByteStr(ref s) => Constant::Binary(Lrc::clone(s)),
|
|
||||||
LitKind::Char(c) => Constant::Char(c),
|
|
||||||
LitKind::Int(n, _) => Constant::Int(n),
|
|
||||||
LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
|
|
||||||
ast::FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()),
|
|
||||||
ast::FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()),
|
|
||||||
},
|
|
||||||
LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind() {
|
|
||||||
ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
|
|
||||||
ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()),
|
|
||||||
_ => bug!(),
|
|
||||||
},
|
|
||||||
LitKind::Bool(b) => Constant::Bool(b),
|
|
||||||
LitKind::Err(s) => Constant::Err(s),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn constant<'tcx>(
|
|
||||||
lcx: &LateContext<'tcx>,
|
|
||||||
typeck_results: &ty::TypeckResults<'tcx>,
|
|
||||||
e: &Expr<'_>,
|
|
||||||
) -> Option<(Constant, bool)> {
|
|
||||||
let mut cx = ConstEvalLateContext {
|
|
||||||
lcx,
|
|
||||||
typeck_results,
|
|
||||||
param_env: lcx.param_env,
|
|
||||||
needed_resolution: false,
|
|
||||||
substs: lcx.tcx.intern_substs(&[]),
|
|
||||||
};
|
|
||||||
cx.expr(e).map(|cst| (cst, cx.needed_resolution))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn constant_simple<'tcx>(
|
|
||||||
lcx: &LateContext<'tcx>,
|
|
||||||
typeck_results: &ty::TypeckResults<'tcx>,
|
|
||||||
e: &Expr<'_>,
|
|
||||||
) -> Option<Constant> {
|
|
||||||
constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`.
|
|
||||||
pub fn constant_context<'a, 'tcx>(
|
|
||||||
lcx: &'a LateContext<'tcx>,
|
|
||||||
typeck_results: &'a ty::TypeckResults<'tcx>,
|
|
||||||
) -> ConstEvalLateContext<'a, 'tcx> {
|
|
||||||
ConstEvalLateContext {
|
|
||||||
lcx,
|
|
||||||
typeck_results,
|
|
||||||
param_env: lcx.param_env,
|
|
||||||
needed_resolution: false,
|
|
||||||
substs: lcx.tcx.intern_substs(&[]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ConstEvalLateContext<'a, 'tcx> {
|
|
||||||
lcx: &'a LateContext<'tcx>,
|
|
||||||
typeck_results: &'a ty::TypeckResults<'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
needed_resolution: bool,
|
|
||||||
substs: SubstsRef<'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|
||||||
/// Simple constant folding: Insert an expression, get a constant or none.
|
|
||||||
pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
|
|
||||||
match e.kind {
|
|
||||||
ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
|
|
||||||
ExprKind::Block(ref block, _) => self.block(block),
|
|
||||||
ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))),
|
|
||||||
ExprKind::Array(ref vec) => self.multi(vec).map(Constant::Vec),
|
|
||||||
ExprKind::Tup(ref tup) => self.multi(tup).map(Constant::Tuple),
|
|
||||||
ExprKind::Repeat(ref value, _) => {
|
|
||||||
let n = match self.typeck_results.expr_ty(e).kind() {
|
|
||||||
ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?,
|
|
||||||
_ => span_bug!(e.span, "typeck error"),
|
|
||||||
};
|
|
||||||
self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
|
|
||||||
},
|
|
||||||
ExprKind::Unary(op, ref operand) => self.expr(operand).and_then(|o| match op {
|
|
||||||
UnOp::Not => self.constant_not(&o, self.typeck_results.expr_ty(e)),
|
|
||||||
UnOp::Neg => self.constant_negate(&o, self.typeck_results.expr_ty(e)),
|
|
||||||
UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }),
|
|
||||||
}),
|
|
||||||
ExprKind::If(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
|
|
||||||
ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right),
|
|
||||||
ExprKind::Call(ref callee, ref args) => {
|
|
||||||
// We only handle a few const functions for now.
|
|
||||||
if_chain! {
|
|
||||||
if args.is_empty();
|
|
||||||
if let ExprKind::Path(qpath) = &callee.kind;
|
|
||||||
let res = self.typeck_results.qpath_res(qpath, callee.hir_id);
|
|
||||||
if let Some(def_id) = res.opt_def_id();
|
|
||||||
let def_path: Vec<_> = self.lcx.get_def_path(def_id).into_iter().map(Symbol::as_str).collect();
|
|
||||||
let def_path: Vec<&str> = def_path.iter().take(4).map(|s| &**s).collect();
|
|
||||||
if let ["core", "num", int_impl, "max_value"] = *def_path;
|
|
||||||
then {
|
|
||||||
let value = match int_impl {
|
|
||||||
"<impl i8>" => i8::MAX as u128,
|
|
||||||
"<impl i16>" => i16::MAX as u128,
|
|
||||||
"<impl i32>" => i32::MAX as u128,
|
|
||||||
"<impl i64>" => i64::MAX as u128,
|
|
||||||
"<impl i128>" => i128::MAX as u128,
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
Some(Constant::Int(value))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ExprKind::Index(ref arr, ref index) => self.index(arr, index),
|
|
||||||
ExprKind::AddrOf(_, _, ref inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
|
|
||||||
// TODO: add other expressions.
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::cast_possible_wrap)]
|
|
||||||
fn constant_not(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
|
|
||||||
use self::Constant::{Bool, Int};
|
|
||||||
match *o {
|
|
||||||
Bool(b) => Some(Bool(!b)),
|
|
||||||
Int(value) => {
|
|
||||||
let value = !value;
|
|
||||||
match *ty.kind() {
|
|
||||||
ty::Int(ity) => Some(Int(unsext(self.lcx.tcx, value as i128, ity))),
|
|
||||||
ty::Uint(ity) => Some(Int(clip(self.lcx.tcx, value, ity))),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn constant_negate(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
|
|
||||||
use self::Constant::{Int, F32, F64};
|
|
||||||
match *o {
|
|
||||||
Int(value) => {
|
|
||||||
let ity = match *ty.kind() {
|
|
||||||
ty::Int(ity) => ity,
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
// sign extend
|
|
||||||
let value = sext(self.lcx.tcx, value, ity);
|
|
||||||
let value = value.checked_neg()?;
|
|
||||||
// clear unused bits
|
|
||||||
Some(Int(unsext(self.lcx.tcx, value, ity)))
|
|
||||||
},
|
|
||||||
F32(f) => Some(F32(-f)),
|
|
||||||
F64(f) => Some(F64(-f)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create `Some(Vec![..])` of all constants, unless there is any
|
|
||||||
/// non-constant part.
|
|
||||||
fn multi(&mut self, vec: &[Expr<'_>]) -> Option<Vec<Constant>> {
|
|
||||||
vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lookup a possibly constant expression from a `ExprKind::Path`.
|
|
||||||
fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<Constant> {
|
|
||||||
let res = self.typeck_results.qpath_res(qpath, id);
|
|
||||||
match res {
|
|
||||||
Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
|
|
||||||
let substs = self.typeck_results.node_substs(id);
|
|
||||||
let substs = if self.substs.is_empty() {
|
|
||||||
substs
|
|
||||||
} else {
|
|
||||||
substs.subst(self.lcx.tcx, self.substs)
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = self
|
|
||||||
.lcx
|
|
||||||
.tcx
|
|
||||||
.const_eval_resolve(
|
|
||||||
self.param_env,
|
|
||||||
ty::WithOptConstParam::unknown(def_id),
|
|
||||||
substs,
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.ok()
|
|
||||||
.map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
|
|
||||||
let result = miri_to_const(&result);
|
|
||||||
if result.is_some() {
|
|
||||||
self.needed_resolution = true;
|
|
||||||
}
|
|
||||||
result
|
|
||||||
},
|
|
||||||
// FIXME: cover all usable cases.
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant> {
|
|
||||||
let lhs = self.expr(lhs);
|
|
||||||
let index = self.expr(index);
|
|
||||||
|
|
||||||
match (lhs, index) {
|
|
||||||
(Some(Constant::Vec(vec)), Some(Constant::Int(index))) => match vec.get(index as usize) {
|
|
||||||
Some(Constant::F32(x)) => Some(Constant::F32(*x)),
|
|
||||||
Some(Constant::F64(x)) => Some(Constant::F64(*x)),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
(Some(Constant::Vec(vec)), _) => {
|
|
||||||
if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) {
|
|
||||||
match vec.get(0) {
|
|
||||||
Some(Constant::F32(x)) => Some(Constant::F32(*x)),
|
|
||||||
Some(Constant::F64(x)) => Some(Constant::F64(*x)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A block can only yield a constant if it only has one constant expression.
|
|
||||||
fn block(&mut self, block: &Block<'_>) -> Option<Constant> {
|
|
||||||
if block.stmts.is_empty() {
|
|
||||||
block.expr.as_ref().and_then(|b| self.expr(b))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant> {
|
|
||||||
if let Some(Constant::Bool(b)) = self.expr(cond) {
|
|
||||||
if b {
|
|
||||||
self.expr(&*then)
|
|
||||||
} else {
|
|
||||||
otherwise.as_ref().and_then(|expr| self.expr(expr))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant> {
|
|
||||||
let l = self.expr(left)?;
|
|
||||||
let r = self.expr(right);
|
|
||||||
match (l, r) {
|
|
||||||
(Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck_results.expr_ty_opt(left)?.kind() {
|
|
||||||
ty::Int(ity) => {
|
|
||||||
let l = sext(self.lcx.tcx, l, ity);
|
|
||||||
let r = sext(self.lcx.tcx, r, ity);
|
|
||||||
let zext = |n: i128| Constant::Int(unsext(self.lcx.tcx, n, ity));
|
|
||||||
match op.node {
|
|
||||||
BinOpKind::Add => l.checked_add(r).map(zext),
|
|
||||||
BinOpKind::Sub => l.checked_sub(r).map(zext),
|
|
||||||
BinOpKind::Mul => l.checked_mul(r).map(zext),
|
|
||||||
BinOpKind::Div if r != 0 => l.checked_div(r).map(zext),
|
|
||||||
BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext),
|
|
||||||
BinOpKind::Shr => l.checked_shr(r.try_into().expect("invalid shift")).map(zext),
|
|
||||||
BinOpKind::Shl => l.checked_shl(r.try_into().expect("invalid shift")).map(zext),
|
|
||||||
BinOpKind::BitXor => Some(zext(l ^ r)),
|
|
||||||
BinOpKind::BitOr => Some(zext(l | r)),
|
|
||||||
BinOpKind::BitAnd => Some(zext(l & r)),
|
|
||||||
BinOpKind::Eq => Some(Constant::Bool(l == r)),
|
|
||||||
BinOpKind::Ne => Some(Constant::Bool(l != r)),
|
|
||||||
BinOpKind::Lt => Some(Constant::Bool(l < r)),
|
|
||||||
BinOpKind::Le => Some(Constant::Bool(l <= r)),
|
|
||||||
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
|
|
||||||
BinOpKind::Gt => Some(Constant::Bool(l > r)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ty::Uint(_) => match op.node {
|
|
||||||
BinOpKind::Add => l.checked_add(r).map(Constant::Int),
|
|
||||||
BinOpKind::Sub => l.checked_sub(r).map(Constant::Int),
|
|
||||||
BinOpKind::Mul => l.checked_mul(r).map(Constant::Int),
|
|
||||||
BinOpKind::Div => l.checked_div(r).map(Constant::Int),
|
|
||||||
BinOpKind::Rem => l.checked_rem(r).map(Constant::Int),
|
|
||||||
BinOpKind::Shr => l.checked_shr(r.try_into().expect("shift too large")).map(Constant::Int),
|
|
||||||
BinOpKind::Shl => l.checked_shl(r.try_into().expect("shift too large")).map(Constant::Int),
|
|
||||||
BinOpKind::BitXor => Some(Constant::Int(l ^ r)),
|
|
||||||
BinOpKind::BitOr => Some(Constant::Int(l | r)),
|
|
||||||
BinOpKind::BitAnd => Some(Constant::Int(l & r)),
|
|
||||||
BinOpKind::Eq => Some(Constant::Bool(l == r)),
|
|
||||||
BinOpKind::Ne => Some(Constant::Bool(l != r)),
|
|
||||||
BinOpKind::Lt => Some(Constant::Bool(l < r)),
|
|
||||||
BinOpKind::Le => Some(Constant::Bool(l <= r)),
|
|
||||||
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
|
|
||||||
BinOpKind::Gt => Some(Constant::Bool(l > r)),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
(Constant::F32(l), Some(Constant::F32(r))) => match op.node {
|
|
||||||
BinOpKind::Add => Some(Constant::F32(l + r)),
|
|
||||||
BinOpKind::Sub => Some(Constant::F32(l - r)),
|
|
||||||
BinOpKind::Mul => Some(Constant::F32(l * r)),
|
|
||||||
BinOpKind::Div => Some(Constant::F32(l / r)),
|
|
||||||
BinOpKind::Rem => Some(Constant::F32(l % r)),
|
|
||||||
BinOpKind::Eq => Some(Constant::Bool(l == r)),
|
|
||||||
BinOpKind::Ne => Some(Constant::Bool(l != r)),
|
|
||||||
BinOpKind::Lt => Some(Constant::Bool(l < r)),
|
|
||||||
BinOpKind::Le => Some(Constant::Bool(l <= r)),
|
|
||||||
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
|
|
||||||
BinOpKind::Gt => Some(Constant::Bool(l > r)),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
(Constant::F64(l), Some(Constant::F64(r))) => match op.node {
|
|
||||||
BinOpKind::Add => Some(Constant::F64(l + r)),
|
|
||||||
BinOpKind::Sub => Some(Constant::F64(l - r)),
|
|
||||||
BinOpKind::Mul => Some(Constant::F64(l * r)),
|
|
||||||
BinOpKind::Div => Some(Constant::F64(l / r)),
|
|
||||||
BinOpKind::Rem => Some(Constant::F64(l % r)),
|
|
||||||
BinOpKind::Eq => Some(Constant::Bool(l == r)),
|
|
||||||
BinOpKind::Ne => Some(Constant::Bool(l != r)),
|
|
||||||
BinOpKind::Lt => Some(Constant::Bool(l < r)),
|
|
||||||
BinOpKind::Le => Some(Constant::Bool(l <= r)),
|
|
||||||
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
|
|
||||||
BinOpKind::Gt => Some(Constant::Bool(l > r)),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
(l, r) => match (op.node, l, r) {
|
|
||||||
(BinOpKind::And, Constant::Bool(false), _) => Some(Constant::Bool(false)),
|
|
||||||
(BinOpKind::Or, Constant::Bool(true), _) => Some(Constant::Bool(true)),
|
|
||||||
(BinOpKind::And, Constant::Bool(true), Some(r)) | (BinOpKind::Or, Constant::Bool(false), Some(r)) => {
|
|
||||||
Some(r)
|
|
||||||
},
|
|
||||||
(BinOpKind::BitXor, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l ^ r)),
|
|
||||||
(BinOpKind::BitAnd, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l & r)),
|
|
||||||
(BinOpKind::BitOr, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l | r)),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
|
|
||||||
use rustc_middle::mir::interpret::ConstValue;
|
|
||||||
match result.val {
|
|
||||||
ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(int))) => {
|
|
||||||
match result.ty.kind() {
|
|
||||||
ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
|
|
||||||
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
|
|
||||||
ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
|
|
||||||
int.try_into().expect("invalid f32 bit representation"),
|
|
||||||
))),
|
|
||||||
ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
|
|
||||||
int.try_into().expect("invalid f64 bit representation"),
|
|
||||||
))),
|
|
||||||
ty::RawPtr(type_and_mut) => {
|
|
||||||
if let ty::Uint(_) = type_and_mut.ty.kind() {
|
|
||||||
return Some(Constant::RawPtr(int.assert_bits(int.size())));
|
|
||||||
}
|
|
||||||
None
|
|
||||||
},
|
|
||||||
// FIXME: implement other conversions.
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind() {
|
|
||||||
ty::Ref(_, tam, _) => match tam.kind() {
|
|
||||||
ty::Str => String::from_utf8(
|
|
||||||
data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)
|
|
||||||
.to_owned(),
|
|
||||||
)
|
|
||||||
.ok()
|
|
||||||
.map(Constant::Str),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind() {
|
|
||||||
ty::Array(sub_type, len) => match sub_type.kind() {
|
|
||||||
ty::Float(FloatTy::F32) => match miri_to_const(len) {
|
|
||||||
Some(Constant::Int(len)) => alloc
|
|
||||||
.inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
|
|
||||||
.to_owned()
|
|
||||||
.chunks(4)
|
|
||||||
.map(|chunk| {
|
|
||||||
Some(Constant::F32(f32::from_le_bytes(
|
|
||||||
chunk.try_into().expect("this shouldn't happen"),
|
|
||||||
)))
|
|
||||||
})
|
|
||||||
.collect::<Option<Vec<Constant>>>()
|
|
||||||
.map(Constant::Vec),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
ty::Float(FloatTy::F64) => match miri_to_const(len) {
|
|
||||||
Some(Constant::Int(len)) => alloc
|
|
||||||
.inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize))
|
|
||||||
.to_owned()
|
|
||||||
.chunks(8)
|
|
||||||
.map(|chunk| {
|
|
||||||
Some(Constant::F64(f64::from_le_bytes(
|
|
||||||
chunk.try_into().expect("this shouldn't happen"),
|
|
||||||
)))
|
|
||||||
})
|
|
||||||
.collect::<Option<Vec<Constant>>>()
|
|
||||||
.map(Constant::Vec),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
// FIXME: implement other array type conversions.
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
// FIXME: implement other conversions.
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
237
clippy_lints/src/default_numeric_fallback.rs
Normal file
237
clippy_lints/src/default_numeric_fallback.rs
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::{
|
||||||
|
intravisit::{walk_expr, walk_stmt, NestedVisitorMap, Visitor},
|
||||||
|
Body, Expr, ExprKind, HirId, Lit, Stmt, StmtKind,
|
||||||
|
};
|
||||||
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
use rustc_middle::{
|
||||||
|
hir::map::Map,
|
||||||
|
ty::{self, FloatTy, IntTy, PolyFnSig, Ty},
|
||||||
|
};
|
||||||
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
|
|
||||||
|
use if_chain::if_chain;
|
||||||
|
|
||||||
|
use crate::utils::{snippet, span_lint_and_sugg};
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// **What it does:** Checks for usage of unconstrained numeric literals which may cause default numeric fallback in type
|
||||||
|
/// inference.
|
||||||
|
///
|
||||||
|
/// Default numeric fallback means that if numeric types have not yet been bound to concrete
|
||||||
|
/// types at the end of type inference, then integer type is bound to `i32`, and similarly
|
||||||
|
/// floating type is bound to `f64`.
|
||||||
|
///
|
||||||
|
/// See [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-int-fallback.md) for more information about the fallback.
|
||||||
|
///
|
||||||
|
/// **Why is this bad?** For those who are very careful about types, default numeric fallback
|
||||||
|
/// can be a pitfall that cause unexpected runtime behavior.
|
||||||
|
///
|
||||||
|
/// **Known problems:** This lint can only be allowed at the function level or above.
|
||||||
|
///
|
||||||
|
/// **Example:**
|
||||||
|
/// ```rust
|
||||||
|
/// let i = 10;
|
||||||
|
/// let f = 1.23;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust
|
||||||
|
/// let i = 10i32;
|
||||||
|
/// let f = 1.23f64;
|
||||||
|
/// ```
|
||||||
|
pub DEFAULT_NUMERIC_FALLBACK,
|
||||||
|
restriction,
|
||||||
|
"usage of unconstrained numeric literals which may cause default numeric fallback."
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]);
|
||||||
|
|
||||||
|
impl LateLintPass<'_> for DefaultNumericFallback {
|
||||||
|
fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
|
||||||
|
let mut visitor = NumericFallbackVisitor::new(cx);
|
||||||
|
visitor.visit_body(body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NumericFallbackVisitor<'a, 'tcx> {
|
||||||
|
/// Stack manages type bound of exprs. The top element holds current expr type.
|
||||||
|
ty_bounds: Vec<TyBound<'tcx>>,
|
||||||
|
|
||||||
|
cx: &'a LateContext<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
|
||||||
|
fn new(cx: &'a LateContext<'tcx>) -> Self {
|
||||||
|
Self {
|
||||||
|
ty_bounds: vec![TyBound::Nothing],
|
||||||
|
cx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check whether a passed literal has potential to cause fallback or not.
|
||||||
|
fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>) {
|
||||||
|
if_chain! {
|
||||||
|
if let Some(ty_bound) = self.ty_bounds.last();
|
||||||
|
if matches!(lit.node,
|
||||||
|
LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed));
|
||||||
|
if !ty_bound.is_integral();
|
||||||
|
then {
|
||||||
|
let suffix = match lit_ty.kind() {
|
||||||
|
ty::Int(IntTy::I32) => "i32",
|
||||||
|
ty::Float(FloatTy::F64) => "f64",
|
||||||
|
// Default numeric fallback never results in other types.
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let sugg = format!("{}_{}", snippet(self.cx, lit.span, ""), suffix);
|
||||||
|
span_lint_and_sugg(
|
||||||
|
self.cx,
|
||||||
|
DEFAULT_NUMERIC_FALLBACK,
|
||||||
|
lit.span,
|
||||||
|
"default numeric fallback might occur",
|
||||||
|
"consider adding suffix",
|
||||||
|
sugg,
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
|
||||||
|
type Map = Map<'tcx>;
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
|
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||||
|
match &expr.kind {
|
||||||
|
ExprKind::Call(func, args) => {
|
||||||
|
if let Some(fn_sig) = fn_sig_opt(self.cx, func.hir_id) {
|
||||||
|
for (expr, bound) in args.iter().zip(fn_sig.skip_binder().inputs().iter()) {
|
||||||
|
// Push found arg type, then visit arg.
|
||||||
|
self.ty_bounds.push(TyBound::Ty(bound));
|
||||||
|
self.visit_expr(expr);
|
||||||
|
self.ty_bounds.pop();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ExprKind::MethodCall(_, _, args, _) => {
|
||||||
|
if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
|
||||||
|
let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
|
||||||
|
for (expr, bound) in args.iter().zip(fn_sig.inputs().iter()) {
|
||||||
|
self.ty_bounds.push(TyBound::Ty(bound));
|
||||||
|
self.visit_expr(expr);
|
||||||
|
self.ty_bounds.pop();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ExprKind::Struct(qpath, fields, base) => {
|
||||||
|
if_chain! {
|
||||||
|
if let Some(def_id) = self.cx.qpath_res(qpath, expr.hir_id).opt_def_id();
|
||||||
|
let ty = self.cx.tcx.type_of(def_id);
|
||||||
|
if let Some(adt_def) = ty.ty_adt_def();
|
||||||
|
if adt_def.is_struct();
|
||||||
|
if let Some(variant) = adt_def.variants.iter().next();
|
||||||
|
then {
|
||||||
|
let fields_def = &variant.fields;
|
||||||
|
|
||||||
|
// Push field type then visit each field expr.
|
||||||
|
for field in fields.iter() {
|
||||||
|
let bound =
|
||||||
|
fields_def
|
||||||
|
.iter()
|
||||||
|
.find_map(|f_def| {
|
||||||
|
if f_def.ident == field.ident
|
||||||
|
{ Some(self.cx.tcx.type_of(f_def.did)) }
|
||||||
|
else { None }
|
||||||
|
});
|
||||||
|
self.ty_bounds.push(bound.into());
|
||||||
|
self.visit_expr(field.expr);
|
||||||
|
self.ty_bounds.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visit base with no bound.
|
||||||
|
if let Some(base) = base {
|
||||||
|
self.ty_bounds.push(TyBound::Nothing);
|
||||||
|
self.visit_expr(base);
|
||||||
|
self.ty_bounds.pop();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ExprKind::Lit(lit) => {
|
||||||
|
let ty = self.cx.typeck_results().expr_ty(expr);
|
||||||
|
self.check_lit(lit, ty);
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
walk_expr(self, expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
|
||||||
|
match stmt.kind {
|
||||||
|
StmtKind::Local(local) => {
|
||||||
|
if local.ty.is_some() {
|
||||||
|
self.ty_bounds.push(TyBound::Any)
|
||||||
|
} else {
|
||||||
|
self.ty_bounds.push(TyBound::Nothing)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => self.ty_bounds.push(TyBound::Nothing),
|
||||||
|
}
|
||||||
|
|
||||||
|
walk_stmt(self, stmt);
|
||||||
|
self.ty_bounds.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||||
|
NestedVisitorMap::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<'tcx>> {
|
||||||
|
let node_ty = cx.typeck_results().node_type_opt(hir_id)?;
|
||||||
|
// We can't use `TyS::fn_sig` because it automatically performs substs, this may result in FNs.
|
||||||
|
match node_ty.kind() {
|
||||||
|
ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id)),
|
||||||
|
ty::FnPtr(fn_sig) => Some(*fn_sig),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum TyBound<'tcx> {
|
||||||
|
Any,
|
||||||
|
Ty(Ty<'tcx>),
|
||||||
|
Nothing,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> TyBound<'tcx> {
|
||||||
|
fn is_integral(self) -> bool {
|
||||||
|
match self {
|
||||||
|
TyBound::Any => true,
|
||||||
|
TyBound::Ty(t) => t.is_integral(),
|
||||||
|
TyBound::Nothing => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> From<Option<Ty<'tcx>>> for TyBound<'tcx> {
|
||||||
|
fn from(v: Option<Ty<'tcx>>) -> Self {
|
||||||
|
match v {
|
||||||
|
Some(t) => TyBound::Ty(t),
|
||||||
|
None => TyBound::Nothing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
implements_trait, is_entrypoint_fn, is_type_diagnostic_item, match_panic_def_id, method_chain_args, return_ty,
|
implements_trait, is_entrypoint_fn, is_expn_of, is_type_diagnostic_item, match_panic_def_id, method_chain_args,
|
||||||
span_lint, span_lint_and_note,
|
return_ty, span_lint, span_lint_and_note,
|
||||||
};
|
};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
@ -216,9 +216,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
||||||
let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
|
let headers = check_attrs(cx, &self.valid_idents, &item.attrs);
|
||||||
match item.kind {
|
match item.kind {
|
||||||
hir::ItemKind::Fn(ref sig, _, body_id) => {
|
hir::ItemKind::Fn(ref sig, _, body_id) => {
|
||||||
if !(is_entrypoint_fn(cx, item.def_id.to_def_id())
|
if !(is_entrypoint_fn(cx, item.def_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
|
||||||
|| in_external_macro(cx.tcx.sess, item.span))
|
|
||||||
{
|
|
||||||
let body = cx.tcx.hir().body(body_id);
|
let body = cx.tcx.hir().body(body_id);
|
||||||
let mut fpu = FindPanicUnwrap {
|
let mut fpu = FindPanicUnwrap {
|
||||||
cx,
|
cx,
|
||||||
|
@ -226,7 +224,15 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
||||||
panic_span: None,
|
panic_span: None,
|
||||||
};
|
};
|
||||||
fpu.visit_expr(&body.value);
|
fpu.visit_expr(&body.value);
|
||||||
lint_for_missing_headers(cx, item.hir_id(), item.span, sig, headers, Some(body_id), fpu.panic_span);
|
lint_for_missing_headers(
|
||||||
|
cx,
|
||||||
|
item.hir_id(),
|
||||||
|
item.span,
|
||||||
|
sig,
|
||||||
|
headers,
|
||||||
|
Some(body_id),
|
||||||
|
fpu.panic_span,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
hir::ItemKind::Impl(ref impl_) => {
|
hir::ItemKind::Impl(ref impl_) => {
|
||||||
|
@ -264,7 +270,15 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
||||||
panic_span: None,
|
panic_span: None,
|
||||||
};
|
};
|
||||||
fpu.visit_expr(&body.value);
|
fpu.visit_expr(&body.value);
|
||||||
lint_for_missing_headers(cx, item.hir_id(), item.span, sig, headers, Some(body_id), fpu.panic_span);
|
lint_for_missing_headers(
|
||||||
|
cx,
|
||||||
|
item.hir_id(),
|
||||||
|
item.span,
|
||||||
|
sig,
|
||||||
|
headers,
|
||||||
|
Some(body_id),
|
||||||
|
fpu.panic_span,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -561,9 +575,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
|
||||||
| ItemKind::ExternCrate(..)
|
| ItemKind::ExternCrate(..)
|
||||||
| ItemKind::ForeignMod(..) => return false,
|
| ItemKind::ForeignMod(..) => return false,
|
||||||
// We found a main function ...
|
// We found a main function ...
|
||||||
ItemKind::Fn(box FnKind(_, sig, _, Some(block)))
|
ItemKind::Fn(box FnKind(_, sig, _, Some(block))) if item.ident.name == sym::main => {
|
||||||
if item.ident.name == sym::main =>
|
|
||||||
{
|
|
||||||
let is_async = matches!(sig.header.asyncness, Async::Yes { .. });
|
let is_async = matches!(sig.header.asyncness, Async::Yes { .. });
|
||||||
let returns_nothing = match &sig.decl.output {
|
let returns_nothing = match &sig.decl.output {
|
||||||
FnRetTy::Default(..) => true,
|
FnRetTy::Default(..) => true,
|
||||||
|
@ -699,6 +711,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
|
||||||
if let ExprKind::Path(QPath::Resolved(_, ref path)) = func_expr.kind;
|
if let ExprKind::Path(QPath::Resolved(_, ref path)) = func_expr.kind;
|
||||||
if let Some(path_def_id) = path.res.opt_def_id();
|
if let Some(path_def_id) = path.res.opt_def_id();
|
||||||
if match_panic_def_id(self.cx, path_def_id);
|
if match_panic_def_id(self.cx, path_def_id);
|
||||||
|
if is_expn_of(expr.span, "unreachable").is_none();
|
||||||
then {
|
then {
|
||||||
self.panic_span = Some(expr.span);
|
self.panic_span = Some(expr.span);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use crate::utils::{attr_by_name, in_macro, match_path_ast, span_lint_and_help};
|
use crate::utils::{attr_by_name, in_macro, match_path_ast, span_lint_and_help};
|
||||||
use rustc_ast::ast::{
|
use rustc_ast::ast::{AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind};
|
||||||
AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind,
|
|
||||||
};
|
|
||||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
101
clippy_lints/src/from_str_radix_10.rs
Normal file
101
clippy_lints/src/from_str_radix_10.rs
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
use if_chain::if_chain;
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::{def, Expr, ExprKind, PrimTy, QPath, TyKind};
|
||||||
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
use rustc_middle::ty::Ty;
|
||||||
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
|
use crate::utils::is_type_diagnostic_item;
|
||||||
|
use crate::utils::span_lint_and_sugg;
|
||||||
|
use crate::utils::sugg::Sugg;
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// **What it does:**
|
||||||
|
/// Checks for function invocations of the form `primitive::from_str_radix(s, 10)`
|
||||||
|
///
|
||||||
|
/// **Why is this bad?**
|
||||||
|
/// This specific common use case can be rewritten as `s.parse::<primitive>()`
|
||||||
|
/// (and in most cases, the turbofish can be removed), which reduces code length
|
||||||
|
/// and complexity.
|
||||||
|
///
|
||||||
|
/// **Known problems:**
|
||||||
|
/// This lint may suggest using (&<expression>).parse() instead of <expression>.parse() directly
|
||||||
|
/// in some cases, which is correct but adds unnecessary complexity to the code.
|
||||||
|
///
|
||||||
|
/// **Example:**
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// let input: &str = get_input();
|
||||||
|
/// let num = u16::from_str_radix(input, 10)?;
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```ignore
|
||||||
|
/// let input: &str = get_input();
|
||||||
|
/// let num: u16 = input.parse()?;
|
||||||
|
/// ```
|
||||||
|
pub FROM_STR_RADIX_10,
|
||||||
|
style,
|
||||||
|
"from_str_radix with radix 10"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]);
|
||||||
|
|
||||||
|
impl LateLintPass<'tcx> for FromStrRadix10 {
|
||||||
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
|
||||||
|
if_chain! {
|
||||||
|
if let ExprKind::Call(maybe_path, arguments) = &exp.kind;
|
||||||
|
if let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind;
|
||||||
|
|
||||||
|
// check if the first part of the path is some integer primitive
|
||||||
|
if let TyKind::Path(ty_qpath) = &ty.kind;
|
||||||
|
let ty_res = cx.qpath_res(ty_qpath, ty.hir_id);
|
||||||
|
if let def::Res::PrimTy(prim_ty) = ty_res;
|
||||||
|
if matches!(prim_ty, PrimTy::Int(_) | PrimTy::Uint(_));
|
||||||
|
|
||||||
|
// check if the second part of the path indeed calls the associated
|
||||||
|
// function `from_str_radix`
|
||||||
|
if pathseg.ident.name.as_str() == "from_str_radix";
|
||||||
|
|
||||||
|
// check if the second argument is a primitive `10`
|
||||||
|
if arguments.len() == 2;
|
||||||
|
if let ExprKind::Lit(lit) = &arguments[1].kind;
|
||||||
|
if let rustc_ast::ast::LitKind::Int(10, _) = lit.node;
|
||||||
|
|
||||||
|
then {
|
||||||
|
let expr = if let ExprKind::AddrOf(_, _, expr) = &arguments[0].kind {
|
||||||
|
let ty = cx.typeck_results().expr_ty(expr);
|
||||||
|
if is_ty_stringish(cx, ty) {
|
||||||
|
expr
|
||||||
|
} else {
|
||||||
|
&arguments[0]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
&arguments[0]
|
||||||
|
};
|
||||||
|
|
||||||
|
let sugg = Sugg::hir_with_applicability(
|
||||||
|
cx,
|
||||||
|
expr,
|
||||||
|
"<string>",
|
||||||
|
&mut Applicability::MachineApplicable
|
||||||
|
).maybe_par();
|
||||||
|
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
FROM_STR_RADIX_10,
|
||||||
|
exp.span,
|
||||||
|
"this call to `from_str_radix` can be replaced with a call to `str::parse`",
|
||||||
|
"try",
|
||||||
|
format!("{}.parse::<{}>()", sugg, prim_ty.name_str()),
|
||||||
|
Applicability::MaybeIncorrect
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if a Ty is `String` or `&str`
|
||||||
|
fn is_ty_stringish(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
|
||||||
|
is_type_diagnostic_item(cx, ty, sym::string_type) || is_type_diagnostic_item(cx, ty, sym::str)
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
attr_by_name, attrs::is_proc_macro, is_must_use_ty, is_trait_impl_item, is_type_diagnostic_item, iter_input_pats,
|
attr_by_name, attrs::is_proc_macro, is_must_use_ty, is_trait_impl_item, is_type_diagnostic_item, iter_input_pats,
|
||||||
last_path_segment, match_def_path, must_use_attr, path_to_local, return_ty, snippet, snippet_opt, span_lint,
|
match_def_path, must_use_attr, path_to_local, return_ty, snippet, snippet_opt, span_lint, span_lint_and_help,
|
||||||
span_lint_and_help, span_lint_and_then, trait_ref_of_method, type_is_unsafe_function,
|
span_lint_and_then, trait_ref_of_method, type_is_unsafe_function,
|
||||||
};
|
};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_ast::ast::Attribute;
|
use rustc_ast::ast::Attribute;
|
||||||
|
@ -470,12 +470,11 @@ fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if !in_external_macro(cx.sess(), item_span);
|
if !in_external_macro(cx.sess(), item_span);
|
||||||
if let hir::FnRetTy::Return(ref ty) = decl.output;
|
if let hir::FnRetTy::Return(ref ty) = decl.output;
|
||||||
if let hir::TyKind::Path(ref qpath) = ty.kind;
|
let ty = hir_ty_to_ty(cx.tcx, ty);
|
||||||
if is_type_diagnostic_item(cx, hir_ty_to_ty(cx.tcx, ty), sym::result_type);
|
if is_type_diagnostic_item(cx, ty, sym::result_type);
|
||||||
if let Some(ref args) = last_path_segment(qpath).args;
|
if let ty::Adt(_, substs) = ty.kind();
|
||||||
if let [_, hir::GenericArg::Type(ref err_ty)] = args.args;
|
let err_ty = substs.type_at(1);
|
||||||
if let hir::TyKind::Tup(t) = err_ty.kind;
|
if err_ty.is_unit();
|
||||||
if t.is_empty();
|
|
||||||
then {
|
then {
|
||||||
span_lint_and_help(
|
span_lint_and_help(
|
||||||
cx,
|
cx,
|
||||||
|
|
134
clippy_lints/src/inconsistent_struct_constructor.rs
Normal file
134
clippy_lints/src/inconsistent_struct_constructor.rs
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::{self as hir, ExprKind};
|
||||||
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
|
use rustc_span::symbol::Symbol;
|
||||||
|
|
||||||
|
use if_chain::if_chain;
|
||||||
|
|
||||||
|
use crate::utils::{snippet, span_lint_and_sugg};
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// **What it does:** Checks for struct constructors where the order of the field init
|
||||||
|
/// shorthand in the constructor is inconsistent with the order in the struct definition.
|
||||||
|
///
|
||||||
|
/// **Why is this bad?** Since the order of fields in a constructor doesn't affect the
|
||||||
|
/// resulted instance as the below example indicates,
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// #[derive(Debug, PartialEq, Eq)]
|
||||||
|
/// struct Foo {
|
||||||
|
/// x: i32,
|
||||||
|
/// y: i32,
|
||||||
|
/// }
|
||||||
|
/// let x = 1;
|
||||||
|
/// let y = 2;
|
||||||
|
///
|
||||||
|
/// // This assertion never fails.
|
||||||
|
/// assert_eq!(Foo { x, y }, Foo { y, x });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// inconsistent order means nothing and just decreases readability and consistency.
|
||||||
|
///
|
||||||
|
/// **Known problems:** None.
|
||||||
|
///
|
||||||
|
/// **Example:**
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// struct Foo {
|
||||||
|
/// x: i32,
|
||||||
|
/// y: i32,
|
||||||
|
/// }
|
||||||
|
/// let x = 1;
|
||||||
|
/// let y = 2;
|
||||||
|
/// Foo { y, x };
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust
|
||||||
|
/// # struct Foo {
|
||||||
|
/// # x: i32,
|
||||||
|
/// # y: i32,
|
||||||
|
/// # }
|
||||||
|
/// # let x = 1;
|
||||||
|
/// # let y = 2;
|
||||||
|
/// Foo { x, y };
|
||||||
|
/// ```
|
||||||
|
pub INCONSISTENT_STRUCT_CONSTRUCTOR,
|
||||||
|
style,
|
||||||
|
"the order of the field init shorthand is inconsistent with the order in the struct definition"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRUCTOR]);
|
||||||
|
|
||||||
|
impl LateLintPass<'_> for InconsistentStructConstructor {
|
||||||
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
||||||
|
if_chain! {
|
||||||
|
if let ExprKind::Struct(qpath, fields, base) = expr.kind;
|
||||||
|
if let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id();
|
||||||
|
let ty = cx.tcx.type_of(def_id);
|
||||||
|
if let Some(adt_def) = ty.ty_adt_def();
|
||||||
|
if adt_def.is_struct();
|
||||||
|
if let Some(variant) = adt_def.variants.iter().next();
|
||||||
|
if fields.iter().all(|f| f.is_shorthand);
|
||||||
|
then {
|
||||||
|
let mut def_order_map = FxHashMap::default();
|
||||||
|
for (idx, field) in variant.fields.iter().enumerate() {
|
||||||
|
def_order_map.insert(field.ident.name, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_consistent_order(fields, &def_order_map) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ordered_fields: Vec<_> = fields.iter().map(|f| f.ident.name).collect();
|
||||||
|
ordered_fields.sort_unstable_by_key(|id| def_order_map[id]);
|
||||||
|
|
||||||
|
let mut fields_snippet = String::new();
|
||||||
|
let (last_ident, idents) = ordered_fields.split_last().unwrap();
|
||||||
|
for ident in idents {
|
||||||
|
fields_snippet.push_str(&format!("{}, ", ident));
|
||||||
|
}
|
||||||
|
fields_snippet.push_str(&last_ident.to_string());
|
||||||
|
|
||||||
|
let base_snippet = if let Some(base) = base {
|
||||||
|
format!(", ..{}", snippet(cx, base.span, ".."))
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
let sugg = format!("{} {{ {}{} }}",
|
||||||
|
snippet(cx, qpath.span(), ".."),
|
||||||
|
fields_snippet,
|
||||||
|
base_snippet,
|
||||||
|
);
|
||||||
|
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
INCONSISTENT_STRUCT_CONSTRUCTOR,
|
||||||
|
expr.span,
|
||||||
|
"inconsistent struct constructor",
|
||||||
|
"try",
|
||||||
|
sugg,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether the order of the fields in the constructor is consistent with the order in the
|
||||||
|
// definition.
|
||||||
|
fn is_consistent_order<'tcx>(fields: &'tcx [hir::Field<'tcx>], def_order_map: &FxHashMap<Symbol, usize>) -> bool {
|
||||||
|
let mut cur_idx = usize::MIN;
|
||||||
|
for f in fields {
|
||||||
|
let next_idx = def_order_map[&f.ident.name];
|
||||||
|
if cur_idx > next_idx {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cur_idx = next_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
|
@ -106,6 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
|
||||||
let decl = &signature.decl;
|
let decl = &signature.decl;
|
||||||
if decl.implicit_self.has_implicit_self();
|
if decl.implicit_self.has_implicit_self();
|
||||||
if decl.inputs.len() == 1;
|
if decl.inputs.len() == 1;
|
||||||
|
if impl_item.generics.params.is_empty();
|
||||||
|
|
||||||
// Check if return type is String
|
// Check if return type is String
|
||||||
if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::string_type);
|
if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::string_type);
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
// error-pattern:cargo-clippy
|
// error-pattern:cargo-clippy
|
||||||
|
|
||||||
#![feature(bindings_after_at)]
|
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(concat_idents)]
|
|
||||||
#![feature(crate_visibility_modifier)]
|
|
||||||
#![feature(drain_filter)]
|
#![feature(drain_filter)]
|
||||||
#![feature(in_band_lifetimes)]
|
#![feature(in_band_lifetimes)]
|
||||||
#![feature(once_cell)]
|
#![feature(once_cell)]
|
||||||
|
@ -149,6 +146,20 @@ macro_rules! declare_clippy_lint {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! sym {
|
||||||
|
( $($x:tt)* ) => { clippy_utils::sym!($($x)*) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! unwrap_cargo_metadata {
|
||||||
|
( $($x:tt)* ) => { clippy_utils::unwrap_cargo_metadata!($($x)*) }
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! extract_msrv_attr {
|
||||||
|
( $($x:tt)* ) => { clippy_utils::extract_msrv_attr!($($x)*); }
|
||||||
|
}
|
||||||
|
|
||||||
mod consts;
|
mod consts;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod utils;
|
mod utils;
|
||||||
|
@ -181,6 +192,7 @@ mod copy_iterator;
|
||||||
mod create_dir;
|
mod create_dir;
|
||||||
mod dbg_macro;
|
mod dbg_macro;
|
||||||
mod default;
|
mod default;
|
||||||
|
mod default_numeric_fallback;
|
||||||
mod dereference;
|
mod dereference;
|
||||||
mod derive;
|
mod derive;
|
||||||
mod disallowed_method;
|
mod disallowed_method;
|
||||||
|
@ -210,6 +222,7 @@ mod floating_point_arithmetic;
|
||||||
mod format;
|
mod format;
|
||||||
mod formatting;
|
mod formatting;
|
||||||
mod from_over_into;
|
mod from_over_into;
|
||||||
|
mod from_str_radix_10;
|
||||||
mod functions;
|
mod functions;
|
||||||
mod future_not_send;
|
mod future_not_send;
|
||||||
mod get_last_with_len;
|
mod get_last_with_len;
|
||||||
|
@ -219,6 +232,7 @@ mod if_let_some_result;
|
||||||
mod if_not_else;
|
mod if_not_else;
|
||||||
mod implicit_return;
|
mod implicit_return;
|
||||||
mod implicit_saturating_sub;
|
mod implicit_saturating_sub;
|
||||||
|
mod inconsistent_struct_constructor;
|
||||||
mod indexing_slicing;
|
mod indexing_slicing;
|
||||||
mod infinite_iter;
|
mod infinite_iter;
|
||||||
mod inherent_impl;
|
mod inherent_impl;
|
||||||
|
@ -239,6 +253,7 @@ mod loops;
|
||||||
mod macro_use;
|
mod macro_use;
|
||||||
mod main_recursion;
|
mod main_recursion;
|
||||||
mod manual_async_fn;
|
mod manual_async_fn;
|
||||||
|
mod manual_map;
|
||||||
mod manual_non_exhaustive;
|
mod manual_non_exhaustive;
|
||||||
mod manual_ok_or;
|
mod manual_ok_or;
|
||||||
mod manual_strip;
|
mod manual_strip;
|
||||||
|
@ -585,6 +600,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
&dbg_macro::DBG_MACRO,
|
&dbg_macro::DBG_MACRO,
|
||||||
&default::DEFAULT_TRAIT_ACCESS,
|
&default::DEFAULT_TRAIT_ACCESS,
|
||||||
&default::FIELD_REASSIGN_WITH_DEFAULT,
|
&default::FIELD_REASSIGN_WITH_DEFAULT,
|
||||||
|
&default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
|
||||||
&dereference::EXPLICIT_DEREF_METHODS,
|
&dereference::EXPLICIT_DEREF_METHODS,
|
||||||
&derive::DERIVE_HASH_XOR_EQ,
|
&derive::DERIVE_HASH_XOR_EQ,
|
||||||
&derive::DERIVE_ORD_XOR_PARTIAL_ORD,
|
&derive::DERIVE_ORD_XOR_PARTIAL_ORD,
|
||||||
|
@ -637,6 +653,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
&formatting::SUSPICIOUS_ELSE_FORMATTING,
|
&formatting::SUSPICIOUS_ELSE_FORMATTING,
|
||||||
&formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
|
&formatting::SUSPICIOUS_UNARY_OP_FORMATTING,
|
||||||
&from_over_into::FROM_OVER_INTO,
|
&from_over_into::FROM_OVER_INTO,
|
||||||
|
&from_str_radix_10::FROM_STR_RADIX_10,
|
||||||
&functions::DOUBLE_MUST_USE,
|
&functions::DOUBLE_MUST_USE,
|
||||||
&functions::MUST_USE_CANDIDATE,
|
&functions::MUST_USE_CANDIDATE,
|
||||||
&functions::MUST_USE_UNIT,
|
&functions::MUST_USE_UNIT,
|
||||||
|
@ -652,6 +669,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
&if_not_else::IF_NOT_ELSE,
|
&if_not_else::IF_NOT_ELSE,
|
||||||
&implicit_return::IMPLICIT_RETURN,
|
&implicit_return::IMPLICIT_RETURN,
|
||||||
&implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
|
&implicit_saturating_sub::IMPLICIT_SATURATING_SUB,
|
||||||
|
&inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR,
|
||||||
&indexing_slicing::INDEXING_SLICING,
|
&indexing_slicing::INDEXING_SLICING,
|
||||||
&indexing_slicing::OUT_OF_BOUNDS_INDEXING,
|
&indexing_slicing::OUT_OF_BOUNDS_INDEXING,
|
||||||
&infinite_iter::INFINITE_ITER,
|
&infinite_iter::INFINITE_ITER,
|
||||||
|
@ -702,6 +720,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
¯o_use::MACRO_USE_IMPORTS,
|
¯o_use::MACRO_USE_IMPORTS,
|
||||||
&main_recursion::MAIN_RECURSION,
|
&main_recursion::MAIN_RECURSION,
|
||||||
&manual_async_fn::MANUAL_ASYNC_FN,
|
&manual_async_fn::MANUAL_ASYNC_FN,
|
||||||
|
&manual_map::MANUAL_MAP,
|
||||||
&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
|
&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
|
||||||
&manual_ok_or::MANUAL_OK_OR,
|
&manual_ok_or::MANUAL_OK_OR,
|
||||||
&manual_strip::MANUAL_STRIP,
|
&manual_strip::MANUAL_STRIP,
|
||||||
|
@ -1031,6 +1050,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
store.register_late_pass(|| box strings::StringAdd);
|
store.register_late_pass(|| box strings::StringAdd);
|
||||||
store.register_late_pass(|| box implicit_return::ImplicitReturn);
|
store.register_late_pass(|| box implicit_return::ImplicitReturn);
|
||||||
store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
|
store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
|
||||||
|
store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback);
|
||||||
|
store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor);
|
||||||
|
|
||||||
let msrv = conf.msrv.as_ref().and_then(|s| {
|
let msrv = conf.msrv.as_ref().and_then(|s| {
|
||||||
parse_msrv(s, None, None).or_else(|| {
|
parse_msrv(s, None, None).or_else(|| {
|
||||||
|
@ -1256,6 +1277,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
store.register_late_pass(move || box types::PtrAsPtr::new(msrv));
|
store.register_late_pass(move || box types::PtrAsPtr::new(msrv));
|
||||||
store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
|
store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
|
||||||
store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
|
store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
|
||||||
|
store.register_late_pass(|| box from_str_radix_10::FromStrRadix10);
|
||||||
|
store.register_late_pass(|| box manual_map::ManualMap);
|
||||||
|
|
||||||
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
|
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
|
||||||
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
|
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
|
||||||
|
@ -1265,6 +1288,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
LintId::of(&asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
|
LintId::of(&asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
|
||||||
LintId::of(&create_dir::CREATE_DIR),
|
LintId::of(&create_dir::CREATE_DIR),
|
||||||
LintId::of(&dbg_macro::DBG_MACRO),
|
LintId::of(&dbg_macro::DBG_MACRO),
|
||||||
|
LintId::of(&default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
|
||||||
LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
|
LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
|
||||||
LintId::of(&exhaustive_items::EXHAUSTIVE_ENUMS),
|
LintId::of(&exhaustive_items::EXHAUSTIVE_ENUMS),
|
||||||
LintId::of(&exhaustive_items::EXHAUSTIVE_STRUCTS),
|
LintId::of(&exhaustive_items::EXHAUSTIVE_STRUCTS),
|
||||||
|
@ -1389,8 +1413,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
LintId::of(&types::PTR_AS_PTR),
|
LintId::of(&types::PTR_AS_PTR),
|
||||||
LintId::of(&unicode::NON_ASCII_LITERAL),
|
LintId::of(&unicode::NON_ASCII_LITERAL),
|
||||||
LintId::of(&unicode::UNICODE_NOT_NFC),
|
LintId::of(&unicode::UNICODE_NOT_NFC),
|
||||||
|
LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS),
|
||||||
LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
|
LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
|
||||||
LintId::of(&unused_self::UNUSED_SELF),
|
LintId::of(&unused_self::UNUSED_SELF),
|
||||||
|
LintId::of(&upper_case_acronyms::UPPER_CASE_ACRONYMS),
|
||||||
LintId::of(&wildcard_imports::ENUM_GLOB_USE),
|
LintId::of(&wildcard_imports::ENUM_GLOB_USE),
|
||||||
LintId::of(&wildcard_imports::WILDCARD_IMPORTS),
|
LintId::of(&wildcard_imports::WILDCARD_IMPORTS),
|
||||||
LintId::of(&zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
|
LintId::of(&zero_sized_map_values::ZERO_SIZED_MAP_VALUES),
|
||||||
|
@ -1468,6 +1494,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING),
|
LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING),
|
||||||
LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
|
LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
|
||||||
LintId::of(&from_over_into::FROM_OVER_INTO),
|
LintId::of(&from_over_into::FROM_OVER_INTO),
|
||||||
|
LintId::of(&from_str_radix_10::FROM_STR_RADIX_10),
|
||||||
LintId::of(&functions::DOUBLE_MUST_USE),
|
LintId::of(&functions::DOUBLE_MUST_USE),
|
||||||
LintId::of(&functions::MUST_USE_UNIT),
|
LintId::of(&functions::MUST_USE_UNIT),
|
||||||
LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF),
|
LintId::of(&functions::NOT_UNSAFE_PTR_ARG_DEREF),
|
||||||
|
@ -1477,6 +1504,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
LintId::of(&identity_op::IDENTITY_OP),
|
LintId::of(&identity_op::IDENTITY_OP),
|
||||||
LintId::of(&if_let_mutex::IF_LET_MUTEX),
|
LintId::of(&if_let_mutex::IF_LET_MUTEX),
|
||||||
LintId::of(&if_let_some_result::IF_LET_SOME_RESULT),
|
LintId::of(&if_let_some_result::IF_LET_SOME_RESULT),
|
||||||
|
LintId::of(&inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
|
||||||
LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING),
|
LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING),
|
||||||
LintId::of(&infinite_iter::INFINITE_ITER),
|
LintId::of(&infinite_iter::INFINITE_ITER),
|
||||||
LintId::of(&inherent_to_string::INHERENT_TO_STRING),
|
LintId::of(&inherent_to_string::INHERENT_TO_STRING),
|
||||||
|
@ -1512,6 +1540,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
LintId::of(&loops::WHILE_LET_ON_ITERATOR),
|
LintId::of(&loops::WHILE_LET_ON_ITERATOR),
|
||||||
LintId::of(&main_recursion::MAIN_RECURSION),
|
LintId::of(&main_recursion::MAIN_RECURSION),
|
||||||
LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
|
LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
|
||||||
|
LintId::of(&manual_map::MANUAL_MAP),
|
||||||
LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
|
LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
|
||||||
LintId::of(&manual_strip::MANUAL_STRIP),
|
LintId::of(&manual_strip::MANUAL_STRIP),
|
||||||
LintId::of(&manual_unwrap_or::MANUAL_UNWRAP_OR),
|
LintId::of(&manual_unwrap_or::MANUAL_UNWRAP_OR),
|
||||||
|
@ -1682,13 +1711,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
|
LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
|
||||||
LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
|
LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
|
||||||
LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
|
LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
|
||||||
LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS),
|
|
||||||
LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
|
LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
|
||||||
LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
|
LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
|
||||||
LintId::of(&unused_unit::UNUSED_UNIT),
|
LintId::of(&unused_unit::UNUSED_UNIT),
|
||||||
LintId::of(&unwrap::PANICKING_UNWRAP),
|
LintId::of(&unwrap::PANICKING_UNWRAP),
|
||||||
LintId::of(&unwrap::UNNECESSARY_UNWRAP),
|
LintId::of(&unwrap::UNNECESSARY_UNWRAP),
|
||||||
LintId::of(&upper_case_acronyms::UPPER_CASE_ACRONYMS),
|
|
||||||
LintId::of(&useless_conversion::USELESS_CONVERSION),
|
LintId::of(&useless_conversion::USELESS_CONVERSION),
|
||||||
LintId::of(&vec::USELESS_VEC),
|
LintId::of(&vec::USELESS_VEC),
|
||||||
LintId::of(&vec_init_then_push::VEC_INIT_THEN_PUSH),
|
LintId::of(&vec_init_then_push::VEC_INIT_THEN_PUSH),
|
||||||
|
@ -1724,10 +1751,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING),
|
LintId::of(&formatting::SUSPICIOUS_ELSE_FORMATTING),
|
||||||
LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
|
LintId::of(&formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
|
||||||
LintId::of(&from_over_into::FROM_OVER_INTO),
|
LintId::of(&from_over_into::FROM_OVER_INTO),
|
||||||
|
LintId::of(&from_str_radix_10::FROM_STR_RADIX_10),
|
||||||
LintId::of(&functions::DOUBLE_MUST_USE),
|
LintId::of(&functions::DOUBLE_MUST_USE),
|
||||||
LintId::of(&functions::MUST_USE_UNIT),
|
LintId::of(&functions::MUST_USE_UNIT),
|
||||||
LintId::of(&functions::RESULT_UNIT_ERR),
|
LintId::of(&functions::RESULT_UNIT_ERR),
|
||||||
LintId::of(&if_let_some_result::IF_LET_SOME_RESULT),
|
LintId::of(&if_let_some_result::IF_LET_SOME_RESULT),
|
||||||
|
LintId::of(&inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
|
||||||
LintId::of(&inherent_to_string::INHERENT_TO_STRING),
|
LintId::of(&inherent_to_string::INHERENT_TO_STRING),
|
||||||
LintId::of(&len_zero::COMPARISON_TO_EMPTY),
|
LintId::of(&len_zero::COMPARISON_TO_EMPTY),
|
||||||
LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
|
LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
|
||||||
|
@ -1741,6 +1770,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
LintId::of(&loops::WHILE_LET_ON_ITERATOR),
|
LintId::of(&loops::WHILE_LET_ON_ITERATOR),
|
||||||
LintId::of(&main_recursion::MAIN_RECURSION),
|
LintId::of(&main_recursion::MAIN_RECURSION),
|
||||||
LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
|
LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
|
||||||
|
LintId::of(&manual_map::MANUAL_MAP),
|
||||||
LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
|
LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
|
||||||
LintId::of(&map_clone::MAP_CLONE),
|
LintId::of(&map_clone::MAP_CLONE),
|
||||||
LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
|
LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
|
||||||
|
@ -1805,7 +1835,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
|
LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
|
||||||
LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
|
LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
|
||||||
LintId::of(&unused_unit::UNUSED_UNIT),
|
LintId::of(&unused_unit::UNUSED_UNIT),
|
||||||
LintId::of(&upper_case_acronyms::UPPER_CASE_ACRONYMS),
|
|
||||||
LintId::of(&write::PRINTLN_EMPTY_STRING),
|
LintId::of(&write::PRINTLN_EMPTY_STRING),
|
||||||
LintId::of(&write::PRINT_LITERAL),
|
LintId::of(&write::PRINT_LITERAL),
|
||||||
LintId::of(&write::PRINT_WITH_NEWLINE),
|
LintId::of(&write::PRINT_WITH_NEWLINE),
|
||||||
|
@ -1899,7 +1928,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||||
LintId::of(&types::UNNECESSARY_CAST),
|
LintId::of(&types::UNNECESSARY_CAST),
|
||||||
LintId::of(&types::VEC_BOX),
|
LintId::of(&types::VEC_BOX),
|
||||||
LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
|
LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
|
||||||
LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS),
|
|
||||||
LintId::of(&unwrap::UNNECESSARY_UNWRAP),
|
LintId::of(&unwrap::UNNECESSARY_UNWRAP),
|
||||||
LintId::of(&useless_conversion::USELESS_CONVERSION),
|
LintId::of(&useless_conversion::USELESS_CONVERSION),
|
||||||
LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
|
LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
|
||||||
|
|
274
clippy_lints/src/manual_map.rs
Normal file
274
clippy_lints/src/manual_map.rs
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
use crate::{
|
||||||
|
map_unit_fn::OPTION_MAP_UNIT_FN,
|
||||||
|
matches::MATCH_AS_REF,
|
||||||
|
utils::{
|
||||||
|
is_allowed, is_type_diagnostic_item, match_def_path, match_var, paths, peel_hir_expr_refs,
|
||||||
|
peel_mid_ty_refs_is_mutable, snippet_with_applicability, span_lint_and_sugg,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use rustc_ast::util::parser::PREC_POSTFIX;
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, Mutability, Pat, PatKind, QPath};
|
||||||
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
|
use rustc_middle::lint::in_external_macro;
|
||||||
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
|
use rustc_span::symbol::{sym, Ident};
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// **What it does:** Checks for usages of `match` which could be implemented using `map`
|
||||||
|
///
|
||||||
|
/// **Why is this bad?** Using the `map` method is clearer and more concise.
|
||||||
|
///
|
||||||
|
/// **Known problems:** None.
|
||||||
|
///
|
||||||
|
/// **Example:**
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// match Some(0) {
|
||||||
|
/// Some(x) => Some(x + 1),
|
||||||
|
/// None => None,
|
||||||
|
/// };
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust
|
||||||
|
/// Some(0).map(|x| x + 1);
|
||||||
|
/// ```
|
||||||
|
pub MANUAL_MAP,
|
||||||
|
style,
|
||||||
|
"reimplementation of `map`"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(ManualMap => [MANUAL_MAP]);
|
||||||
|
|
||||||
|
impl LateLintPass<'_> for ManualMap {
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
|
if in_external_macro(cx.sess(), expr.span) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let ExprKind::Match(scrutinee, [arm1 @ Arm { guard: None, .. }, arm2 @ Arm { guard: None, .. }], _) =
|
||||||
|
expr.kind
|
||||||
|
{
|
||||||
|
let (scrutinee_ty, ty_ref_count, ty_mutability) =
|
||||||
|
peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrutinee));
|
||||||
|
if !is_type_diagnostic_item(cx, scrutinee_ty, sym::option_type)
|
||||||
|
|| !is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::option_type)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (some_expr, some_pat, pat_ref_count, is_wild_none) =
|
||||||
|
match (try_parse_pattern(cx, arm1.pat), try_parse_pattern(cx, arm2.pat)) {
|
||||||
|
(Some(OptionPat::Wild), Some(OptionPat::Some { pattern, ref_count }))
|
||||||
|
if is_none_expr(cx, arm1.body) =>
|
||||||
|
{
|
||||||
|
(arm2.body, pattern, ref_count, true)
|
||||||
|
},
|
||||||
|
(Some(OptionPat::None), Some(OptionPat::Some { pattern, ref_count }))
|
||||||
|
if is_none_expr(cx, arm1.body) =>
|
||||||
|
{
|
||||||
|
(arm2.body, pattern, ref_count, false)
|
||||||
|
},
|
||||||
|
(Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::Wild))
|
||||||
|
if is_none_expr(cx, arm2.body) =>
|
||||||
|
{
|
||||||
|
(arm1.body, pattern, ref_count, true)
|
||||||
|
},
|
||||||
|
(Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::None))
|
||||||
|
if is_none_expr(cx, arm2.body) =>
|
||||||
|
{
|
||||||
|
(arm1.body, pattern, ref_count, false)
|
||||||
|
},
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Top level or patterns aren't allowed in closures.
|
||||||
|
if matches!(some_pat.kind, PatKind::Or(_)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let some_expr = match get_some_expr(cx, some_expr) {
|
||||||
|
Some(expr) => expr,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
if cx.typeck_results().expr_ty(some_expr) == cx.tcx.types.unit
|
||||||
|
&& !is_allowed(cx, OPTION_MAP_UNIT_FN, expr.hir_id)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine which binding mode to use.
|
||||||
|
let explicit_ref = some_pat.contains_explicit_ref_binding();
|
||||||
|
let binding_ref = explicit_ref.or_else(|| (ty_ref_count != pat_ref_count).then(|| ty_mutability));
|
||||||
|
|
||||||
|
let as_ref_str = match binding_ref {
|
||||||
|
Some(Mutability::Mut) => ".as_mut()",
|
||||||
|
Some(Mutability::Not) => ".as_ref()",
|
||||||
|
None => "",
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut app = Applicability::MachineApplicable;
|
||||||
|
|
||||||
|
// Remove address-of expressions from the scrutinee. `as_ref` will be called,
|
||||||
|
// the type is copyable, or the option is being passed by value.
|
||||||
|
let scrutinee = peel_hir_expr_refs(scrutinee).0;
|
||||||
|
let scrutinee_str = snippet_with_applicability(cx, scrutinee.span, "_", &mut app);
|
||||||
|
let scrutinee_str = if expr.precedence().order() < PREC_POSTFIX {
|
||||||
|
// Parens are needed to chain method calls.
|
||||||
|
format!("({})", scrutinee_str)
|
||||||
|
} else {
|
||||||
|
scrutinee_str.into()
|
||||||
|
};
|
||||||
|
|
||||||
|
let body_str = if let PatKind::Binding(annotation, _, some_binding, None) = some_pat.kind {
|
||||||
|
if let Some(func) = can_pass_as_func(cx, some_binding, some_expr) {
|
||||||
|
snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
|
||||||
|
} else {
|
||||||
|
if match_var(some_expr, some_binding.name)
|
||||||
|
&& !is_allowed(cx, MATCH_AS_REF, expr.hir_id)
|
||||||
|
&& binding_ref.is_some()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `ref` and `ref mut` annotations were handled earlier.
|
||||||
|
let annotation = if matches!(annotation, BindingAnnotation::Mutable) {
|
||||||
|
"mut "
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
format!(
|
||||||
|
"|{}{}| {}",
|
||||||
|
annotation,
|
||||||
|
some_binding,
|
||||||
|
snippet_with_applicability(cx, some_expr.span, "..", &mut app)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if !is_wild_none && explicit_ref.is_none() {
|
||||||
|
// TODO: handle explicit reference annotations.
|
||||||
|
format!(
|
||||||
|
"|{}| {}",
|
||||||
|
snippet_with_applicability(cx, some_pat.span, "..", &mut app),
|
||||||
|
snippet_with_applicability(cx, some_expr.span, "..", &mut app)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Refutable bindings and mixed reference annotations can't be handled by `map`.
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
MANUAL_MAP,
|
||||||
|
expr.span,
|
||||||
|
"manual implementation of `Option::map`",
|
||||||
|
"try this",
|
||||||
|
format!("{}{}.map({})", scrutinee_str, as_ref_str, body_str),
|
||||||
|
app,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether the expression could be passed as a function, or whether a closure is needed.
|
||||||
|
// Returns the function to be passed to `map` if it exists.
|
||||||
|
fn can_pass_as_func(cx: &LateContext<'tcx>, binding: Ident, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
||||||
|
match expr.kind {
|
||||||
|
ExprKind::Call(func, [arg])
|
||||||
|
if match_var(arg, binding.name) && cx.typeck_results().expr_adjustments(arg).is_empty() =>
|
||||||
|
{
|
||||||
|
Some(func)
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum OptionPat<'a> {
|
||||||
|
Wild,
|
||||||
|
None,
|
||||||
|
Some {
|
||||||
|
// The pattern contained in the `Some` tuple.
|
||||||
|
pattern: &'a Pat<'a>,
|
||||||
|
// The number of references before the `Some` tuple.
|
||||||
|
// e.g. `&&Some(_)` has a ref count of 2.
|
||||||
|
ref_count: usize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to parse into a recognized `Option` pattern.
|
||||||
|
// i.e. `_`, `None`, `Some(..)`, or a reference to any of those.
|
||||||
|
fn try_parse_pattern(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) -> Option<OptionPat<'tcx>> {
|
||||||
|
fn f(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ref_count: usize) -> Option<OptionPat<'tcx>> {
|
||||||
|
match pat.kind {
|
||||||
|
PatKind::Wild => Some(OptionPat::Wild),
|
||||||
|
PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1),
|
||||||
|
PatKind::Path(QPath::Resolved(None, path))
|
||||||
|
if path
|
||||||
|
.res
|
||||||
|
.opt_def_id()
|
||||||
|
.map_or(false, |id| match_def_path(cx, id, &paths::OPTION_NONE)) =>
|
||||||
|
{
|
||||||
|
Some(OptionPat::None)
|
||||||
|
},
|
||||||
|
PatKind::TupleStruct(QPath::Resolved(None, path), [pattern], _)
|
||||||
|
if path
|
||||||
|
.res
|
||||||
|
.opt_def_id()
|
||||||
|
.map_or(false, |id| match_def_path(cx, id, &paths::OPTION_SOME)) =>
|
||||||
|
{
|
||||||
|
Some(OptionPat::Some { pattern, ref_count })
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f(cx, pat, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks for an expression wrapped by the `Some` constructor. Returns the contained expression.
|
||||||
|
fn get_some_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
|
||||||
|
// TODO: Allow more complex expressions.
|
||||||
|
match expr.kind {
|
||||||
|
ExprKind::Call(
|
||||||
|
Expr {
|
||||||
|
kind: ExprKind::Path(QPath::Resolved(None, path)),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
[arg],
|
||||||
|
) => {
|
||||||
|
if match_def_path(cx, path.res.opt_def_id()?, &paths::OPTION_SOME) {
|
||||||
|
Some(arg)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ExprKind::Block(
|
||||||
|
Block {
|
||||||
|
stmts: [],
|
||||||
|
expr: Some(expr),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
_,
|
||||||
|
) => get_some_expr(cx, expr),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks for the `None` value.
|
||||||
|
fn is_none_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
|
||||||
|
match expr.kind {
|
||||||
|
ExprKind::Path(QPath::Resolved(None, path)) => path
|
||||||
|
.res
|
||||||
|
.opt_def_id()
|
||||||
|
.map_or(false, |id| match_def_path(cx, id, &paths::OPTION_NONE)),
|
||||||
|
ExprKind::Block(
|
||||||
|
Block {
|
||||||
|
stmts: [],
|
||||||
|
expr: Some(expr),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
_,
|
||||||
|
) => is_none_expr(cx, expr),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,19 +3,19 @@ use crate::utils::sugg::Sugg;
|
||||||
use crate::utils::visitors::LocalUsedVisitor;
|
use crate::utils::visitors::LocalUsedVisitor;
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
expr_block, get_parent_expr, implements_trait, in_macro, indent_of, is_allowed, is_expn_of, is_refutable,
|
expr_block, get_parent_expr, implements_trait, in_macro, indent_of, is_allowed, is_expn_of, is_refutable,
|
||||||
is_type_diagnostic_item, is_wild, match_qpath, match_type, meets_msrv, multispan_sugg, path_to_local_id,
|
is_type_diagnostic_item, is_wild, match_qpath, match_type, meets_msrv, multispan_sugg, path_to_local,
|
||||||
peel_hir_pat_refs, peel_mid_ty_refs, peel_n_hir_expr_refs, remove_blocks, snippet, snippet_block, snippet_opt,
|
path_to_local_id, peel_hir_pat_refs, peel_mid_ty_refs, peel_n_hir_expr_refs, remove_blocks, snippet, snippet_block,
|
||||||
snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
|
snippet_opt, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
|
||||||
strip_pat_refs,
|
span_lint_and_then, strip_pat_refs,
|
||||||
};
|
};
|
||||||
use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash};
|
use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_ast::ast::LitKind;
|
use rustc_ast::ast::LitKind;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::def::CtorKind;
|
use rustc_hir::def::CtorKind;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, Local, MatchSource, Mutability, Node, Pat,
|
Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, HirId, Local, MatchSource, Mutability, Node, Pat,
|
||||||
PatKind, QPath, RangeEnd,
|
PatKind, QPath, RangeEnd,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
|
@ -24,7 +24,7 @@ use rustc_middle::ty::{self, Ty, TyS};
|
||||||
use rustc_semver::RustcVersion;
|
use rustc_semver::RustcVersion;
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::source_map::{Span, Spanned};
|
use rustc_span::source_map::{Span, Spanned};
|
||||||
use rustc_span::{sym, Symbol};
|
use rustc_span::sym;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::collections::Bound;
|
use std::collections::Bound;
|
||||||
|
@ -1873,13 +1873,6 @@ fn test_overlapping() {
|
||||||
|
|
||||||
/// Implementation of `MATCH_SAME_ARMS`.
|
/// Implementation of `MATCH_SAME_ARMS`.
|
||||||
fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) {
|
fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) {
|
||||||
fn same_bindings<'tcx>(lhs: &FxHashMap<Symbol, Ty<'tcx>>, rhs: &FxHashMap<Symbol, Ty<'tcx>>) -> bool {
|
|
||||||
lhs.len() == rhs.len()
|
|
||||||
&& lhs
|
|
||||||
.iter()
|
|
||||||
.all(|(name, l_ty)| rhs.get(name).map_or(false, |r_ty| TyS::same_type(l_ty, r_ty)))
|
|
||||||
}
|
|
||||||
|
|
||||||
if let ExprKind::Match(_, ref arms, MatchSource::Normal) = expr.kind {
|
if let ExprKind::Match(_, ref arms, MatchSource::Normal) = expr.kind {
|
||||||
let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 {
|
let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 {
|
||||||
let mut h = SpanlessHash::new(cx);
|
let mut h = SpanlessHash::new(cx);
|
||||||
|
@ -1891,12 +1884,38 @@ fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) {
|
||||||
let min_index = usize::min(lindex, rindex);
|
let min_index = usize::min(lindex, rindex);
|
||||||
let max_index = usize::max(lindex, rindex);
|
let max_index = usize::max(lindex, rindex);
|
||||||
|
|
||||||
|
let mut local_map: FxHashMap<HirId, HirId> = FxHashMap::default();
|
||||||
|
let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
|
||||||
|
if_chain! {
|
||||||
|
if let Some(a_id) = path_to_local(a);
|
||||||
|
if let Some(b_id) = path_to_local(b);
|
||||||
|
let entry = match local_map.entry(a_id) {
|
||||||
|
Entry::Vacant(entry) => entry,
|
||||||
|
// check if using the same bindings as before
|
||||||
|
Entry::Occupied(entry) => return *entry.get() == b_id,
|
||||||
|
};
|
||||||
|
// the names technically don't have to match; this makes the lint more conservative
|
||||||
|
if cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id);
|
||||||
|
if TyS::same_type(cx.typeck_results().expr_ty(a), cx.typeck_results().expr_ty(b));
|
||||||
|
if pat_contains_local(lhs.pat, a_id);
|
||||||
|
if pat_contains_local(rhs.pat, b_id);
|
||||||
|
then {
|
||||||
|
entry.insert(b_id);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
// Arms with a guard are ignored, those can’t always be merged together
|
// Arms with a guard are ignored, those can’t always be merged together
|
||||||
// This is also the case for arms in-between each there is an arm with a guard
|
// This is also the case for arms in-between each there is an arm with a guard
|
||||||
(min_index..=max_index).all(|index| arms[index].guard.is_none()) &&
|
(min_index..=max_index).all(|index| arms[index].guard.is_none())
|
||||||
SpanlessEq::new(cx).eq_expr(&lhs.body, &rhs.body) &&
|
&& SpanlessEq::new(cx)
|
||||||
// all patterns should have the same bindings
|
.expr_fallback(eq_fallback)
|
||||||
same_bindings(&bindings(cx, &lhs.pat), &bindings(cx, &rhs.pat))
|
.eq_expr(&lhs.body, &rhs.body)
|
||||||
|
// these checks could be removed to allow unused bindings
|
||||||
|
&& bindings_eq(lhs.pat, local_map.keys().copied().collect())
|
||||||
|
&& bindings_eq(rhs.pat, local_map.values().copied().collect())
|
||||||
};
|
};
|
||||||
|
|
||||||
let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
|
let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
|
||||||
|
@ -1939,50 +1958,18 @@ fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the list of bindings in a pattern.
|
fn pat_contains_local(pat: &Pat<'_>, id: HirId) -> bool {
|
||||||
fn bindings<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>) -> FxHashMap<Symbol, Ty<'tcx>> {
|
let mut result = false;
|
||||||
fn bindings_impl<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, map: &mut FxHashMap<Symbol, Ty<'tcx>>) {
|
pat.walk_short(|p| {
|
||||||
match pat.kind {
|
result |= matches!(p.kind, PatKind::Binding(_, binding_id, ..) if binding_id == id);
|
||||||
PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map),
|
!result
|
||||||
PatKind::TupleStruct(_, pats, _) => {
|
});
|
||||||
for pat in pats {
|
|
||||||
bindings_impl(cx, pat, map);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
PatKind::Binding(.., ident, ref as_pat) => {
|
|
||||||
if let Entry::Vacant(v) = map.entry(ident.name) {
|
|
||||||
v.insert(cx.typeck_results().pat_ty(pat));
|
|
||||||
}
|
|
||||||
if let Some(ref as_pat) = *as_pat {
|
|
||||||
bindings_impl(cx, as_pat, map);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
PatKind::Or(fields) | PatKind::Tuple(fields, _) => {
|
|
||||||
for pat in fields {
|
|
||||||
bindings_impl(cx, pat, map);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
PatKind::Struct(_, fields, _) => {
|
|
||||||
for pat in fields {
|
|
||||||
bindings_impl(cx, &pat.pat, map);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
PatKind::Slice(lhs, ref mid, rhs) => {
|
|
||||||
for pat in lhs {
|
|
||||||
bindings_impl(cx, pat, map);
|
|
||||||
}
|
|
||||||
if let Some(ref mid) = *mid {
|
|
||||||
bindings_impl(cx, mid, map);
|
|
||||||
}
|
|
||||||
for pat in rhs {
|
|
||||||
bindings_impl(cx, pat, map);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild | PatKind::Path(..) => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut result = FxHashMap::default();
|
|
||||||
bindings_impl(cx, pat, &mut result);
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if all the bindings in the `Pat` are in `ids` and vice versa
|
||||||
|
fn bindings_eq(pat: &Pat<'_>, mut ids: FxHashSet<HirId>) -> bool {
|
||||||
|
let mut result = true;
|
||||||
|
pat.each_binding_or_first(&mut |_, id, _, _| result &= ids.remove(&id));
|
||||||
|
result && ids.is_empty()
|
||||||
|
}
|
||||||
|
|
|
@ -90,10 +90,6 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
|
||||||
self.found = true;
|
self.found = true;
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
ExprKind::If(..) => {
|
|
||||||
self.found = true;
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
ExprKind::Path(_) => {
|
ExprKind::Path(_) => {
|
||||||
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
|
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
|
||||||
if adj
|
if adj
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::utils::{span_lint, span_lint_and_then};
|
use crate::utils::{span_lint, span_lint_and_then};
|
||||||
use rustc_ast::ast::{
|
use rustc_ast::ast::{
|
||||||
Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, FnKind, Item, ItemKind, Local, Pat,
|
Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, FnKind, Item, ItemKind, Local, Pat, PatKind,
|
||||||
PatKind,
|
|
||||||
};
|
};
|
||||||
use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
|
use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
|
||||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||||
|
|
|
@ -212,10 +212,10 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
|
||||||
if !expr_borrows(cx, left_expr) {
|
if !expr_borrows(cx, left_expr) {
|
||||||
return Some(LintTrigger::SortByKey(SortByKeyDetection {
|
return Some(LintTrigger::SortByKey(SortByKeyDetection {
|
||||||
vec_name,
|
vec_name,
|
||||||
unstable,
|
|
||||||
closure_arg,
|
closure_arg,
|
||||||
closure_body,
|
closure_body,
|
||||||
reverse
|
reverse,
|
||||||
|
unstable,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
contains_return, in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then,
|
contains_return, in_macro, match_qpath, paths, return_ty, snippet, span_lint_and_then,
|
||||||
visitors::find_all_ret_expressions,
|
visitors::find_all_ret_expressions,
|
||||||
};
|
};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
|
@ -7,7 +7,7 @@ use rustc_errors::Applicability;
|
||||||
use rustc_hir::intravisit::FnKind;
|
use rustc_hir::intravisit::FnKind;
|
||||||
use rustc_hir::{Body, ExprKind, FnDecl, HirId, Impl, ItemKind, Node};
|
use rustc_hir::{Body, ExprKind, FnDecl, HirId, Impl, ItemKind, Node};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::ty::subst::GenericArgKind;
|
use rustc_middle::ty;
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -17,8 +17,8 @@ declare_clippy_lint! {
|
||||||
///
|
///
|
||||||
/// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned.
|
/// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned.
|
||||||
///
|
///
|
||||||
/// **Known problems:** Since this lint changes function type signature, you may need to
|
/// **Known problems:** There can be false positives if the function signature is designed to
|
||||||
/// adjust some code at callee side.
|
/// fit some external requirement.
|
||||||
///
|
///
|
||||||
/// **Example:**
|
/// **Example:**
|
||||||
///
|
///
|
||||||
|
@ -48,7 +48,7 @@ declare_clippy_lint! {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub UNNECESSARY_WRAPS,
|
pub UNNECESSARY_WRAPS,
|
||||||
complexity,
|
pedantic,
|
||||||
"functions that only return `Ok` or `Some`"
|
"functions that only return `Ok` or `Some`"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
|
||||||
span: Span,
|
span: Span,
|
||||||
hir_id: HirId,
|
hir_id: HirId,
|
||||||
) {
|
) {
|
||||||
|
// Abort if public function/method or closure.
|
||||||
match fn_kind {
|
match fn_kind {
|
||||||
FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => {
|
FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => {
|
||||||
if visibility.node.is_pub() {
|
if visibility.node.is_pub() {
|
||||||
|
@ -74,6 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Abort if the method is implementing a trait or of it a trait method.
|
||||||
if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
|
if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
|
||||||
if matches!(
|
if matches!(
|
||||||
item.kind,
|
item.kind,
|
||||||
|
@ -83,25 +85,44 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::option_type) {
|
// Get the wrapper and inner types, if can't, abort.
|
||||||
("Option", &paths::OPTION_SOME)
|
let (return_type_label, path, inner_type) = if let ty::Adt(adt_def, subst) = return_ty(cx, hir_id).kind() {
|
||||||
} else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) {
|
if cx.tcx.is_diagnostic_item(sym::option_type, adt_def.did) {
|
||||||
("Result", &paths::RESULT_OK)
|
("Option", &paths::OPTION_SOME, subst.type_at(0))
|
||||||
|
} else if cx.tcx.is_diagnostic_item(sym::result_type, adt_def.did) {
|
||||||
|
("Result", &paths::RESULT_OK, subst.type_at(0))
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Check if all return expression respect the following condition and collect them.
|
||||||
let mut suggs = Vec::new();
|
let mut suggs = Vec::new();
|
||||||
let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
|
let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if !in_macro(ret_expr.span);
|
if !in_macro(ret_expr.span);
|
||||||
|
// Check if a function call.
|
||||||
if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
|
if let ExprKind::Call(ref func, ref args) = ret_expr.kind;
|
||||||
|
// Get the Path of the function call.
|
||||||
if let ExprKind::Path(ref qpath) = func.kind;
|
if let ExprKind::Path(ref qpath) = func.kind;
|
||||||
|
// Check if OPTION_SOME or RESULT_OK, depending on return type.
|
||||||
if match_qpath(qpath, path);
|
if match_qpath(qpath, path);
|
||||||
if args.len() == 1;
|
if args.len() == 1;
|
||||||
|
// Make sure the function argument does not contain a return expression.
|
||||||
if !contains_return(&args[0]);
|
if !contains_return(&args[0]);
|
||||||
then {
|
then {
|
||||||
suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string()));
|
suggs.push(
|
||||||
|
(
|
||||||
|
ret_expr.span,
|
||||||
|
if inner_type.is_unit() {
|
||||||
|
"".to_string()
|
||||||
|
} else {
|
||||||
|
snippet(cx, args[0].span.source_callsite(), "..").to_string()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -110,39 +131,34 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
|
||||||
});
|
});
|
||||||
|
|
||||||
if can_sugg && !suggs.is_empty() {
|
if can_sugg && !suggs.is_empty() {
|
||||||
span_lint_and_then(
|
let (lint_msg, return_type_sugg_msg, return_type_sugg, body_sugg_msg) = if inner_type.is_unit() {
|
||||||
cx,
|
(
|
||||||
UNNECESSARY_WRAPS,
|
"this function's return value is unnecessary".to_string(),
|
||||||
span,
|
"remove the return type...".to_string(),
|
||||||
format!(
|
snippet(cx, fn_decl.output.span(), "..").to_string(),
|
||||||
"this function's return value is unnecessarily wrapped by `{}`",
|
"...and then remove returned values",
|
||||||
return_type
|
|
||||||
)
|
)
|
||||||
.as_str(),
|
} else {
|
||||||
|diag| {
|
(
|
||||||
let inner_ty = return_ty(cx, hir_id)
|
format!(
|
||||||
.walk()
|
"this function's return value is unnecessarily wrapped by `{}`",
|
||||||
.skip(1) // skip `std::option::Option` or `std::result::Result`
|
return_type_label
|
||||||
.take(1) // take the first outermost inner type
|
),
|
||||||
.filter_map(|inner| match inner.unpack() {
|
format!("remove `{}` from the return type...", return_type_label),
|
||||||
GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()),
|
inner_type.to_string(),
|
||||||
_ => None,
|
"...and then change returning expressions",
|
||||||
});
|
)
|
||||||
inner_ty.for_each(|inner_ty| {
|
};
|
||||||
diag.span_suggestion(
|
|
||||||
fn_decl.output.span(),
|
span_lint_and_then(cx, UNNECESSARY_WRAPS, span, lint_msg.as_str(), |diag| {
|
||||||
format!("remove `{}` from the return type...", return_type).as_str(),
|
diag.span_suggestion(
|
||||||
inner_ty,
|
fn_decl.output.span(),
|
||||||
Applicability::MaybeIncorrect,
|
return_type_sugg_msg.as_str(),
|
||||||
);
|
return_type_sugg,
|
||||||
});
|
Applicability::MaybeIncorrect,
|
||||||
diag.multipart_suggestion(
|
);
|
||||||
"...and change the returning expressions",
|
diag.multipart_suggestion(body_sugg_msg, suggs, Applicability::MaybeIncorrect);
|
||||||
suggs,
|
});
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ declare_clippy_lint! {
|
||||||
/// struct HttpResponse;
|
/// struct HttpResponse;
|
||||||
/// ```
|
/// ```
|
||||||
pub UPPER_CASE_ACRONYMS,
|
pub UPPER_CASE_ACRONYMS,
|
||||||
style,
|
pedantic,
|
||||||
"capitalized acronyms are against the naming convention"
|
"capitalized acronyms are against the naming convention"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
|
use crate::utils::{in_macro, meets_msrv, snippet_opt, span_lint_and_sugg};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
|
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::intravisit::{walk_item, walk_path, walk_ty, NestedVisitorMap, Visitor};
|
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
def, FnDecl, FnRetTy, FnSig, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Path, PathSegment, QPath,
|
def,
|
||||||
TyKind,
|
def_id::LocalDefId,
|
||||||
|
intravisit::{walk_ty, NestedVisitorMap, Visitor},
|
||||||
|
Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Node, Path, PathSegment,
|
||||||
|
QPath, TyKind,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_middle::hir::map::Map;
|
use rustc_middle::hir::map::Map;
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::ty::{AssocKind, Ty, TyS};
|
||||||
use rustc_middle::ty;
|
|
||||||
use rustc_middle::ty::{DefIdTree, Ty};
|
|
||||||
use rustc_semver::RustcVersion;
|
use rustc_semver::RustcVersion;
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::symbol::kw;
|
use rustc_span::{BytePos, Span};
|
||||||
use rustc_typeck::hir_ty_to_ty;
|
use rustc_typeck::hir_ty_to_ty;
|
||||||
|
|
||||||
use crate::utils::{differing_macro_contexts, meets_msrv, span_lint_and_sugg};
|
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// **What it does:** Checks for unnecessary repetition of structure name when a
|
/// **What it does:** Checks for unnecessary repetition of structure name when a
|
||||||
/// replacement with `Self` is applicable.
|
/// replacement with `Self` is applicable.
|
||||||
|
@ -28,10 +28,11 @@ declare_clippy_lint! {
|
||||||
/// feels inconsistent.
|
/// feels inconsistent.
|
||||||
///
|
///
|
||||||
/// **Known problems:**
|
/// **Known problems:**
|
||||||
/// - False positive when using associated types ([#2843](https://github.com/rust-lang/rust-clippy/issues/2843))
|
/// - Unaddressed false negative in fn bodies of trait implementations
|
||||||
/// - False positives in some situations when using generics ([#3410](https://github.com/rust-lang/rust-clippy/issues/3410))
|
/// - False positive with assotiated types in traits (#4140)
|
||||||
///
|
///
|
||||||
/// **Example:**
|
/// **Example:**
|
||||||
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// struct Foo {}
|
/// struct Foo {}
|
||||||
/// impl Foo {
|
/// impl Foo {
|
||||||
|
@ -54,52 +55,326 @@ declare_clippy_lint! {
|
||||||
"unnecessary structure name repetition whereas `Self` is applicable"
|
"unnecessary structure name repetition whereas `Self` is applicable"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct UseSelf {
|
||||||
|
msrv: Option<RustcVersion>,
|
||||||
|
stack: Vec<StackItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
const USE_SELF_MSRV: RustcVersion = RustcVersion::new(1, 37, 0);
|
||||||
|
|
||||||
|
impl UseSelf {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(msrv: Option<RustcVersion>) -> Self {
|
||||||
|
Self {
|
||||||
|
msrv,
|
||||||
|
..Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum StackItem {
|
||||||
|
Check {
|
||||||
|
hir_id: HirId,
|
||||||
|
impl_trait_ref_def_id: Option<LocalDefId>,
|
||||||
|
types_to_skip: Vec<HirId>,
|
||||||
|
types_to_lint: Vec<HirId>,
|
||||||
|
},
|
||||||
|
NoCheck,
|
||||||
|
}
|
||||||
|
|
||||||
impl_lint_pass!(UseSelf => [USE_SELF]);
|
impl_lint_pass!(UseSelf => [USE_SELF]);
|
||||||
|
|
||||||
const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";
|
const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";
|
||||||
|
|
||||||
fn span_use_self_lint(cx: &LateContext<'_>, path: &Path<'_>, last_segment: Option<&PathSegment<'_>>) {
|
impl<'tcx> LateLintPass<'tcx> for UseSelf {
|
||||||
let last_segment = last_segment.unwrap_or_else(|| path.segments.last().expect(SEGMENTS_MSG));
|
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||||
|
// We push the self types of `impl`s on a stack here. Only the top type on the stack is
|
||||||
// Path segments only include actual path, no methods or fields.
|
// relevant for linting, since this is the self type of the `impl` we're currently in. To
|
||||||
let last_path_span = last_segment.ident.span;
|
// avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that
|
||||||
|
// we're in an `impl` or nested item, that we don't want to lint
|
||||||
if differing_macro_contexts(path.span, last_path_span) {
|
//
|
||||||
return;
|
// NB: If you push something on the stack in this method, remember to also pop it in the
|
||||||
|
// `check_item_post` method.
|
||||||
|
match &item.kind {
|
||||||
|
ItemKind::Impl(Impl {
|
||||||
|
self_ty: hir_self_ty,
|
||||||
|
of_trait,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
let should_check = if let TyKind::Path(QPath::Resolved(_, ref item_path)) = hir_self_ty.kind {
|
||||||
|
let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
|
||||||
|
parameters.as_ref().map_or(true, |params| {
|
||||||
|
!params.parenthesized && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
let impl_trait_ref_def_id = of_trait.as_ref().map(|_| cx.tcx.hir().local_def_id(item.hir_id()));
|
||||||
|
if should_check {
|
||||||
|
self.stack.push(StackItem::Check {
|
||||||
|
hir_id: hir_self_ty.hir_id,
|
||||||
|
impl_trait_ref_def_id,
|
||||||
|
types_to_lint: Vec::new(),
|
||||||
|
types_to_skip: Vec::new(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.stack.push(StackItem::NoCheck);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ItemKind::Static(..)
|
||||||
|
| ItemKind::Const(..)
|
||||||
|
| ItemKind::Fn(..)
|
||||||
|
| ItemKind::Enum(..)
|
||||||
|
| ItemKind::Struct(..)
|
||||||
|
| ItemKind::Union(..)
|
||||||
|
| ItemKind::Trait(..) => {
|
||||||
|
self.stack.push(StackItem::NoCheck);
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only take path up to the end of last_path_span.
|
fn check_item_post(&mut self, _: &LateContext<'_>, item: &Item<'_>) {
|
||||||
let span = path.span.with_hi(last_path_span.hi());
|
use ItemKind::{Const, Enum, Fn, Impl, Static, Struct, Trait, Union};
|
||||||
|
match item.kind {
|
||||||
|
Impl { .. } | Static(..) | Const(..) | Fn(..) | Enum(..) | Struct(..) | Union(..) | Trait(..) => {
|
||||||
|
self.stack.pop();
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
span_lint_and_sugg(
|
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
|
||||||
cx,
|
// We want to skip types in trait `impl`s that aren't declared as `Self` in the trait
|
||||||
USE_SELF,
|
// declaration. The collection of those types is all this method implementation does.
|
||||||
span,
|
if_chain! {
|
||||||
"unnecessary structure name repetition",
|
if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind;
|
||||||
"use the applicable keyword",
|
if let Some(&mut StackItem::Check {
|
||||||
"Self".to_owned(),
|
impl_trait_ref_def_id: Some(def_id),
|
||||||
Applicability::MachineApplicable,
|
ref mut types_to_skip,
|
||||||
);
|
..
|
||||||
|
}) = self.stack.last_mut();
|
||||||
|
if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(def_id);
|
||||||
|
then {
|
||||||
|
// `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
|
||||||
|
// `Self`.
|
||||||
|
let self_ty = impl_trait_ref.self_ty();
|
||||||
|
|
||||||
|
// `trait_method_sig` is the signature of the function, how it is declared in the
|
||||||
|
// trait, not in the impl of the trait.
|
||||||
|
let trait_method = cx
|
||||||
|
.tcx
|
||||||
|
.associated_items(impl_trait_ref.def_id)
|
||||||
|
.find_by_name_and_kind(cx.tcx, impl_item.ident, AssocKind::Fn, impl_trait_ref.def_id)
|
||||||
|
.expect("impl method matches a trait method");
|
||||||
|
let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
|
||||||
|
let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig);
|
||||||
|
|
||||||
|
// `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the
|
||||||
|
// implementation of the trait.
|
||||||
|
let output_hir_ty = if let FnRetTy::Return(ty) = &decl.output {
|
||||||
|
Some(&**ty)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let impl_inputs_outputs = decl.inputs.iter().chain(output_hir_ty);
|
||||||
|
|
||||||
|
// `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature.
|
||||||
|
//
|
||||||
|
// `trait_sem_ty` (of type `ty::Ty`) is the semantic type for the signature in the
|
||||||
|
// trait declaration. This is used to check if `Self` was used in the trait
|
||||||
|
// declaration.
|
||||||
|
//
|
||||||
|
// If `any`where in the `trait_sem_ty` the `self_ty` was used verbatim (as opposed
|
||||||
|
// to `Self`), we want to skip linting that type and all subtypes of it. This
|
||||||
|
// avoids suggestions to e.g. replace `Vec<u8>` with `Vec<Self>`, in an `impl Trait
|
||||||
|
// for u8`, when the trait always uses `Vec<u8>`.
|
||||||
|
//
|
||||||
|
// See also https://github.com/rust-lang/rust-clippy/issues/2894.
|
||||||
|
for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) {
|
||||||
|
if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) {
|
||||||
|
let mut visitor = SkipTyCollector::default();
|
||||||
|
visitor.visit_ty(&impl_hir_ty);
|
||||||
|
types_to_skip.extend(visitor.types_to_skip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) {
|
||||||
|
// `hir_ty_to_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies
|
||||||
|
// we can use `cx.typeck_results.node_type(..)` to get the `ty::Ty` from a `hir::Ty`.
|
||||||
|
// However the `node_type()` method can *only* be called in bodies.
|
||||||
|
//
|
||||||
|
// This method implementation determines which types should get linted in a `Body` and
|
||||||
|
// which shouldn't, with a visitor. We could directly lint in the visitor, but then we
|
||||||
|
// could only allow this lint on item scope. And we would have to check if those types are
|
||||||
|
// already dealt with in `check_ty` anyway.
|
||||||
|
if let Some(StackItem::Check {
|
||||||
|
hir_id,
|
||||||
|
types_to_lint,
|
||||||
|
types_to_skip,
|
||||||
|
..
|
||||||
|
}) = self.stack.last_mut()
|
||||||
|
{
|
||||||
|
let self_ty = ty_from_hir_id(cx, *hir_id);
|
||||||
|
|
||||||
|
let mut visitor = LintTyCollector {
|
||||||
|
cx,
|
||||||
|
self_ty,
|
||||||
|
types_to_lint: vec![],
|
||||||
|
types_to_skip: vec![],
|
||||||
|
};
|
||||||
|
visitor.visit_expr(&body.value);
|
||||||
|
types_to_lint.extend(visitor.types_to_lint);
|
||||||
|
types_to_skip.extend(visitor.types_to_skip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
|
||||||
|
if in_macro(hir_ty.span) | in_impl(cx, hir_ty) | !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lint_dependend_on_expr_kind = if let Some(StackItem::Check {
|
||||||
|
hir_id,
|
||||||
|
types_to_lint,
|
||||||
|
types_to_skip,
|
||||||
|
..
|
||||||
|
}) = self.stack.last()
|
||||||
|
{
|
||||||
|
if types_to_skip.contains(&hir_ty.hir_id) {
|
||||||
|
false
|
||||||
|
} else if types_to_lint.contains(&hir_ty.hir_id) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
let self_ty = ty_from_hir_id(cx, *hir_id);
|
||||||
|
should_lint_ty(hir_ty, hir_ty_to_ty(cx.tcx, hir_ty), self_ty)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if lint_dependend_on_expr_kind {
|
||||||
|
// FIXME: this span manipulation should not be necessary
|
||||||
|
// @flip1995 found an ast lowering issue in
|
||||||
|
// https://github.com/rust-lang/rust/blob/master/src/librustc_ast_lowering/path.rs#l142-l162
|
||||||
|
match cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_ty.hir_id)) {
|
||||||
|
Some(Node::Expr(Expr {
|
||||||
|
kind: ExprKind::Path(QPath::TypeRelative(_, segment)),
|
||||||
|
..
|
||||||
|
})) => span_lint_until_last_segment(cx, hir_ty.span, segment),
|
||||||
|
_ => span_lint(cx, hir_ty.span),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
|
fn expr_ty_matches(cx: &LateContext<'_>, expr: &Expr<'_>, self_ty: Ty<'_>) -> bool {
|
||||||
|
let def_id = expr.hir_id.owner;
|
||||||
|
if cx.tcx.has_typeck_results(def_id) {
|
||||||
|
cx.tcx.typeck(def_id).expr_ty_opt(expr) == Some(self_ty)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if in_macro(expr.span) | !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(StackItem::Check { hir_id, .. }) = self.stack.last() {
|
||||||
|
let self_ty = ty_from_hir_id(cx, *hir_id);
|
||||||
|
|
||||||
|
match &expr.kind {
|
||||||
|
ExprKind::Struct(QPath::Resolved(_, path), ..) => {
|
||||||
|
if expr_ty_matches(cx, expr, self_ty) {
|
||||||
|
match path.res {
|
||||||
|
def::Res::SelfTy(..) => (),
|
||||||
|
def::Res::Def(DefKind::Variant, _) => span_lint_on_path_until_last_segment(cx, path),
|
||||||
|
_ => {
|
||||||
|
span_lint(cx, path.span);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// tuple struct instantiation (`Foo(arg)` or `Enum::Foo(arg)`)
|
||||||
|
ExprKind::Call(fun, _) => {
|
||||||
|
if let Expr {
|
||||||
|
kind: ExprKind::Path(ref qpath),
|
||||||
|
..
|
||||||
|
} = fun
|
||||||
|
{
|
||||||
|
if expr_ty_matches(cx, expr, self_ty) {
|
||||||
|
let res = cx.qpath_res(qpath, fun.hir_id);
|
||||||
|
|
||||||
|
if let def::Res::Def(DefKind::Ctor(ctor_of, _), ..) = res {
|
||||||
|
match ctor_of {
|
||||||
|
def::CtorOf::Variant => {
|
||||||
|
span_lint_on_qpath_resolved(cx, qpath, true);
|
||||||
|
},
|
||||||
|
def::CtorOf::Struct => {
|
||||||
|
span_lint_on_qpath_resolved(cx, qpath, false);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// unit enum variants (`Enum::A`)
|
||||||
|
ExprKind::Path(qpath) => {
|
||||||
|
if expr_ty_matches(cx, expr, self_ty) {
|
||||||
|
span_lint_on_qpath_resolved(cx, &qpath, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_msrv_attr!(LateContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: always use this (more correct) visitor, not just in method signatures.
|
#[derive(Default)]
|
||||||
struct SemanticUseSelfVisitor<'a, 'tcx> {
|
struct SkipTyCollector {
|
||||||
|
types_to_skip: Vec<HirId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Visitor<'tcx> for SkipTyCollector {
|
||||||
|
type Map = Map<'tcx>;
|
||||||
|
|
||||||
|
fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) {
|
||||||
|
self.types_to_skip.push(hir_ty.hir_id);
|
||||||
|
|
||||||
|
walk_ty(self, hir_ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||||
|
NestedVisitorMap::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LintTyCollector<'a, 'tcx> {
|
||||||
cx: &'a LateContext<'tcx>,
|
cx: &'a LateContext<'tcx>,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
types_to_lint: Vec<HirId>,
|
||||||
|
types_to_skip: Vec<HirId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> Visitor<'tcx> for SemanticUseSelfVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> Visitor<'tcx> for LintTyCollector<'a, 'tcx> {
|
||||||
type Map = Map<'tcx>;
|
type Map = Map<'tcx>;
|
||||||
|
|
||||||
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'_>) {
|
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'_>) {
|
||||||
if let TyKind::Path(QPath::Resolved(_, path)) = &hir_ty.kind {
|
if_chain! {
|
||||||
match path.res {
|
if let Some(ty) = self.cx.typeck_results().node_type_opt(hir_ty.hir_id);
|
||||||
def::Res::SelfTy(..) => {},
|
if should_lint_ty(hir_ty, ty, self.self_ty);
|
||||||
_ => {
|
then {
|
||||||
if hir_ty_to_ty(self.cx.tcx, hir_ty) == self.self_ty {
|
self.types_to_lint.push(hir_ty.hir_id);
|
||||||
span_use_self_lint(self.cx, path, None);
|
} else {
|
||||||
}
|
self.types_to_skip.push(hir_ty.hir_id);
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,177 +386,78 @@ impl<'a, 'tcx> Visitor<'tcx> for SemanticUseSelfVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_trait_method_impl_decl<'tcx>(
|
fn span_lint(cx: &LateContext<'_>, span: Span) {
|
||||||
cx: &LateContext<'tcx>,
|
span_lint_and_sugg(
|
||||||
impl_item: &ImplItem<'_>,
|
cx,
|
||||||
impl_decl: &'tcx FnDecl<'_>,
|
USE_SELF,
|
||||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
span,
|
||||||
) {
|
"unnecessary structure name repetition",
|
||||||
let trait_method = cx
|
"use the applicable keyword",
|
||||||
.tcx
|
"Self".to_owned(),
|
||||||
.associated_items(impl_trait_ref.def_id)
|
Applicability::MachineApplicable,
|
||||||
.find_by_name_and_kind(cx.tcx, impl_item.ident, ty::AssocKind::Fn, impl_trait_ref.def_id)
|
);
|
||||||
.expect("impl method matches a trait method");
|
}
|
||||||
|
|
||||||
let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig);
|
fn span_lint_until_last_segment(cx: &LateContext<'_>, span: Span, segment: &PathSegment<'_>) {
|
||||||
|
let sp = span.with_hi(segment.ident.span.lo());
|
||||||
let output_hir_ty = if let FnRetTy::Return(ty) = &impl_decl.output {
|
// remove the trailing ::
|
||||||
Some(&**ty)
|
let span_without_last_segment = match snippet_opt(cx, sp) {
|
||||||
} else {
|
Some(snippet) => match snippet.rfind("::") {
|
||||||
None
|
Some(bidx) => sp.with_hi(sp.lo() + BytePos(bidx as u32)),
|
||||||
|
None => sp,
|
||||||
|
},
|
||||||
|
None => sp,
|
||||||
};
|
};
|
||||||
|
span_lint(cx, span_without_last_segment);
|
||||||
|
}
|
||||||
|
|
||||||
// `impl_hir_ty` (of type `hir::Ty`) represents the type written in the signature.
|
fn span_lint_on_path_until_last_segment(cx: &LateContext<'_>, path: &Path<'_>) {
|
||||||
// `trait_ty` (of type `ty::Ty`) is the semantic type for the signature in the trait.
|
if path.segments.len() > 1 {
|
||||||
// We use `impl_hir_ty` to see if the type was written as `Self`,
|
span_lint_until_last_segment(cx, path.span, path.segments.last().unwrap());
|
||||||
// `hir_ty_to_ty(...)` to check semantic types of paths, and
|
}
|
||||||
// `trait_ty` to determine which parts of the signature in the trait, mention
|
}
|
||||||
// the type being implemented verbatim (as opposed to `Self`).
|
|
||||||
for (impl_hir_ty, trait_ty) in impl_decl
|
|
||||||
.inputs
|
|
||||||
.iter()
|
|
||||||
.chain(output_hir_ty)
|
|
||||||
.zip(trait_method_sig.inputs_and_output)
|
|
||||||
{
|
|
||||||
// Check if the input/output type in the trait method specifies the implemented
|
|
||||||
// type verbatim, and only suggest `Self` if that isn't the case.
|
|
||||||
// This avoids suggestions to e.g. replace `Vec<u8>` with `Vec<Self>`,
|
|
||||||
// in an `impl Trait for u8`, when the trait always uses `Vec<u8>`.
|
|
||||||
// See also https://github.com/rust-lang/rust-clippy/issues/2894.
|
|
||||||
let self_ty = impl_trait_ref.self_ty();
|
|
||||||
if !trait_ty.walk().any(|inner| inner == self_ty.into()) {
|
|
||||||
let mut visitor = SemanticUseSelfVisitor { cx, self_ty };
|
|
||||||
|
|
||||||
visitor.visit_ty(&impl_hir_ty);
|
fn span_lint_on_qpath_resolved(cx: &LateContext<'_>, qpath: &QPath<'_>, until_last_segment: bool) {
|
||||||
|
if let QPath::Resolved(_, path) = qpath {
|
||||||
|
if until_last_segment {
|
||||||
|
span_lint_on_path_until_last_segment(cx, path);
|
||||||
|
} else {
|
||||||
|
span_lint(cx, path.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const USE_SELF_MSRV: RustcVersion = RustcVersion::new(1, 37, 0);
|
fn ty_from_hir_id<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Ty<'tcx> {
|
||||||
|
if let Some(Node::Ty(hir_ty)) = cx.tcx.hir().find(hir_id) {
|
||||||
pub struct UseSelf {
|
hir_ty_to_ty(cx.tcx, hir_ty)
|
||||||
msrv: Option<RustcVersion>,
|
} else {
|
||||||
}
|
unreachable!("This function should only be called with `HirId`s that are for sure `Node::Ty`")
|
||||||
|
|
||||||
impl UseSelf {
|
|
||||||
#[must_use]
|
|
||||||
pub fn new(msrv: Option<RustcVersion>) -> Self {
|
|
||||||
Self { msrv }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for UseSelf {
|
fn in_impl(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> bool {
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
let map = cx.tcx.hir();
|
||||||
if !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV) {
|
let parent = map.get_parent_node(hir_ty.hir_id);
|
||||||
return;
|
if_chain! {
|
||||||
}
|
if let Some(Node::Item(item)) = map.find(parent);
|
||||||
|
if let ItemKind::Impl { .. } = item.kind;
|
||||||
if in_external_macro(cx.sess(), item.span) {
|
then {
|
||||||
return;
|
true
|
||||||
}
|
} else {
|
||||||
if_chain! {
|
false
|
||||||
if let ItemKind::Impl(impl_) = &item.kind;
|
|
||||||
if let TyKind::Path(QPath::Resolved(_, ref item_path)) = impl_.self_ty.kind;
|
|
||||||
then {
|
|
||||||
let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
|
|
||||||
let should_check = parameters.as_ref().map_or(
|
|
||||||
true,
|
|
||||||
|params| !params.parenthesized
|
|
||||||
&&!params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
|
|
||||||
);
|
|
||||||
|
|
||||||
if should_check {
|
|
||||||
let visitor = &mut UseSelfVisitor {
|
|
||||||
item_path,
|
|
||||||
cx,
|
|
||||||
};
|
|
||||||
let impl_trait_ref = cx.tcx.impl_trait_ref(item.def_id);
|
|
||||||
|
|
||||||
if let Some(impl_trait_ref) = impl_trait_ref {
|
|
||||||
for impl_item_ref in impl_.items {
|
|
||||||
let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
|
|
||||||
if let ImplItemKind::Fn(FnSig{ decl: impl_decl, .. }, impl_body_id)
|
|
||||||
= &impl_item.kind {
|
|
||||||
check_trait_method_impl_decl(cx, impl_item, impl_decl, impl_trait_ref);
|
|
||||||
|
|
||||||
let body = cx.tcx.hir().body(*impl_body_id);
|
|
||||||
visitor.visit_body(body);
|
|
||||||
} else {
|
|
||||||
visitor.visit_impl_item(impl_item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for impl_item_ref in impl_.items {
|
|
||||||
let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
|
|
||||||
visitor.visit_impl_item(impl_item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
extract_msrv_attr!(LateContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UseSelfVisitor<'a, 'tcx> {
|
fn should_lint_ty(hir_ty: &hir::Ty<'_>, ty: Ty<'_>, self_ty: Ty<'_>) -> bool {
|
||||||
item_path: &'a Path<'a>,
|
if_chain! {
|
||||||
cx: &'a LateContext<'tcx>,
|
if TyS::same_type(ty, self_ty);
|
||||||
}
|
if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
|
||||||
|
then {
|
||||||
impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
|
!matches!(path.res, def::Res::SelfTy(..))
|
||||||
type Map = Map<'tcx>;
|
} else {
|
||||||
|
false
|
||||||
fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
|
|
||||||
if !path.segments.iter().any(|p| p.ident.span.is_dummy()) {
|
|
||||||
if path.segments.len() >= 2 {
|
|
||||||
let last_but_one = &path.segments[path.segments.len() - 2];
|
|
||||||
if last_but_one.ident.name != kw::SelfUpper {
|
|
||||||
let enum_def_id = match path.res {
|
|
||||||
Res::Def(DefKind::Variant, variant_def_id) => self.cx.tcx.parent(variant_def_id),
|
|
||||||
Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), ctor_def_id) => {
|
|
||||||
let variant_def_id = self.cx.tcx.parent(ctor_def_id);
|
|
||||||
variant_def_id.and_then(|def_id| self.cx.tcx.parent(def_id))
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.item_path.res.opt_def_id() == enum_def_id {
|
|
||||||
span_use_self_lint(self.cx, path, Some(last_but_one));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if path.segments.last().expect(SEGMENTS_MSG).ident.name != kw::SelfUpper {
|
|
||||||
if self.item_path.res == path.res {
|
|
||||||
span_use_self_lint(self.cx, path, None);
|
|
||||||
} else if let Res::Def(DefKind::Ctor(def::CtorOf::Struct, _), ctor_def_id) = path.res {
|
|
||||||
if self.item_path.res.opt_def_id() == self.cx.tcx.parent(ctor_def_id) {
|
|
||||||
span_use_self_lint(self.cx, path, None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
walk_path(self, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_item(&mut self, item: &'tcx Item<'_>) {
|
|
||||||
match item.kind {
|
|
||||||
ItemKind::Use(..)
|
|
||||||
| ItemKind::Static(..)
|
|
||||||
| ItemKind::Enum(..)
|
|
||||||
| ItemKind::Struct(..)
|
|
||||||
| ItemKind::Union(..)
|
|
||||||
| ItemKind::Impl { .. }
|
|
||||||
| ItemKind::Fn(..) => {
|
|
||||||
// Don't check statements that shadow `Self` or where `Self` can't be used
|
|
||||||
},
|
|
||||||
_ => walk_item(self, item),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
|
||||||
NestedVisitorMap::All(self.cx.tcx.hir())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,7 @@ define_Conf! {
|
||||||
"NaN", "NaNs",
|
"NaN", "NaNs",
|
||||||
"OAuth", "GraphQL",
|
"OAuth", "GraphQL",
|
||||||
"OCaml",
|
"OCaml",
|
||||||
"OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap",
|
"OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS",
|
||||||
"WebGL",
|
"WebGL",
|
||||||
"TensorFlow",
|
"TensorFlow",
|
||||||
"TrueType",
|
"TrueType",
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::utils::{
|
||||||
span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq,
|
span_lint, span_lint_and_help, span_lint_and_sugg, SpanlessEq,
|
||||||
};
|
};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, NodeId};
|
use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, ModKind, NodeId};
|
||||||
use rustc_ast::visit::FnKind;
|
use rustc_ast::visit::FnKind;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
@ -301,17 +301,12 @@ declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
|
||||||
|
|
||||||
impl EarlyLintPass for ClippyLintsInternal {
|
impl EarlyLintPass for ClippyLintsInternal {
|
||||||
fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &AstCrate) {
|
fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &AstCrate) {
|
||||||
if let Some(utils) = krate
|
if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") {
|
||||||
.module
|
if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind {
|
||||||
.items
|
if let Some(paths) = items.iter().find(|item| item.ident.name.as_str() == "paths") {
|
||||||
.iter()
|
if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = paths.kind {
|
||||||
.find(|item| item.ident.name.as_str() == "utils")
|
|
||||||
{
|
|
||||||
if let ItemKind::Mod(ref utils_mod) = utils.kind {
|
|
||||||
if let Some(paths) = utils_mod.items.iter().find(|item| item.ident.name.as_str() == "paths") {
|
|
||||||
if let ItemKind::Mod(ref paths_mod) = paths.kind {
|
|
||||||
let mut last_name: Option<SymbolStr> = None;
|
let mut last_name: Option<SymbolStr> = None;
|
||||||
for item in &*paths_mod.items {
|
for item in items {
|
||||||
let name = item.ident.as_str();
|
let name = item.ident.as_str();
|
||||||
if let Some(ref last_name) = last_name {
|
if let Some(ref last_name) = last_name {
|
||||||
if **last_name > *name {
|
if **last_name > *name {
|
||||||
|
@ -343,7 +338,7 @@ impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
|
impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||||
if !run_lints(cx, &[DEFAULT_LINT], item.hir_id) {
|
if !run_lints(cx, &[DEFAULT_LINT], item.hir_id()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,7 +388,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
|
||||||
.find(|iiref| iiref.ident.as_str() == "get_lints")
|
.find(|iiref| iiref.ident.as_str() == "get_lints")
|
||||||
.expect("LintPass needs to implement get_lints")
|
.expect("LintPass needs to implement get_lints")
|
||||||
.id
|
.id
|
||||||
.hir_id,
|
.hir_id(),
|
||||||
);
|
);
|
||||||
collector.visit_expr(&cx.tcx.hir().body(body_id).value);
|
collector.visit_expr(&cx.tcx.hir().body(body_id).value);
|
||||||
}
|
}
|
||||||
|
@ -861,7 +856,7 @@ declare_lint_pass!(InvalidPaths => [INVALID_PATHS]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
|
impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||||
let local_def_id = &cx.tcx.parent_module(item.hir_id);
|
let local_def_id = &cx.tcx.parent_module(item.hir_id());
|
||||||
let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
|
let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if mod_name.as_str() == "paths";
|
if mod_name.as_str() == "paths";
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,12 +1,14 @@
|
||||||
use crate::utils::{is_type_diagnostic_item, match_def_path, paths, snippet, span_lint_and_sugg};
|
use crate::utils::{
|
||||||
|
is_type_diagnostic_item, match_def_path, path_to_local, path_to_local_id, paths, snippet, span_lint_and_sugg,
|
||||||
|
};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_ast::ast::LitKind;
|
use rustc_ast::ast::LitKind;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, Local, PatKind, QPath, Stmt, StmtKind};
|
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::{symbol::sym, Span, Symbol};
|
use rustc_span::{symbol::sym, Span};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
|
@ -45,8 +47,8 @@ enum VecInitKind {
|
||||||
WithCapacity(u64),
|
WithCapacity(u64),
|
||||||
}
|
}
|
||||||
struct VecPushSearcher {
|
struct VecPushSearcher {
|
||||||
|
local_id: HirId,
|
||||||
init: VecInitKind,
|
init: VecInitKind,
|
||||||
name: Symbol,
|
|
||||||
lhs_is_local: bool,
|
lhs_is_local: bool,
|
||||||
lhs_span: Span,
|
lhs_span: Span,
|
||||||
err_span: Span,
|
err_span: Span,
|
||||||
|
@ -81,17 +83,20 @@ impl VecPushSearcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LateLintPass<'_> for VecInitThenPush {
|
impl LateLintPass<'_> for VecInitThenPush {
|
||||||
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
|
fn check_block(&mut self, _: &LateContext<'tcx>, _: &'tcx Block<'tcx>) {
|
||||||
self.searcher = None;
|
self.searcher = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if !in_external_macro(cx.sess(), local.span);
|
if !in_external_macro(cx.sess(), local.span);
|
||||||
if let Some(init) = local.init;
|
if let Some(init) = local.init;
|
||||||
if let PatKind::Binding(BindingAnnotation::Mutable, _, ident, None) = local.pat.kind;
|
if let PatKind::Binding(BindingAnnotation::Mutable, id, _, None) = local.pat.kind;
|
||||||
if let Some(init_kind) = get_vec_init_kind(cx, init);
|
if let Some(init_kind) = get_vec_init_kind(cx, init);
|
||||||
then {
|
then {
|
||||||
self.searcher = Some(VecPushSearcher {
|
self.searcher = Some(VecPushSearcher {
|
||||||
|
local_id: id,
|
||||||
init: init_kind,
|
init: init_kind,
|
||||||
name: ident.name,
|
|
||||||
lhs_is_local: true,
|
lhs_is_local: true,
|
||||||
lhs_span: local.ty.map_or(local.pat.span, |t| local.pat.span.to(t.span)),
|
lhs_span: local.ty.map_or(local.pat.span, |t| local.pat.span.to(t.span)),
|
||||||
err_span: local.span,
|
err_span: local.span,
|
||||||
|
@ -106,13 +111,12 @@ impl LateLintPass<'_> for VecInitThenPush {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if !in_external_macro(cx.sess(), expr.span);
|
if !in_external_macro(cx.sess(), expr.span);
|
||||||
if let ExprKind::Assign(left, right, _) = expr.kind;
|
if let ExprKind::Assign(left, right, _) = expr.kind;
|
||||||
if let ExprKind::Path(QPath::Resolved(_, path)) = left.kind;
|
if let Some(id) = path_to_local(left);
|
||||||
if let Some(name) = path.segments.get(0);
|
|
||||||
if let Some(init_kind) = get_vec_init_kind(cx, right);
|
if let Some(init_kind) = get_vec_init_kind(cx, right);
|
||||||
then {
|
then {
|
||||||
self.searcher = Some(VecPushSearcher {
|
self.searcher = Some(VecPushSearcher {
|
||||||
|
local_id: id,
|
||||||
init: init_kind,
|
init: init_kind,
|
||||||
name: name.ident.name,
|
|
||||||
lhs_is_local: false,
|
lhs_is_local: false,
|
||||||
lhs_span: left.span,
|
lhs_span: left.span,
|
||||||
err_span: expr.span,
|
err_span: expr.span,
|
||||||
|
@ -128,10 +132,8 @@ impl LateLintPass<'_> for VecInitThenPush {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind;
|
if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind;
|
||||||
if let ExprKind::MethodCall(path, _, [self_arg, _], _) = expr.kind;
|
if let ExprKind::MethodCall(path, _, [self_arg, _], _) = expr.kind;
|
||||||
|
if path_to_local_id(self_arg, searcher.local_id);
|
||||||
if path.ident.name.as_str() == "push";
|
if path.ident.name.as_str() == "push";
|
||||||
if let ExprKind::Path(QPath::Resolved(_, self_path)) = self_arg.kind;
|
|
||||||
if let [self_name] = self_path.segments;
|
|
||||||
if self_name.ident.name == searcher.name;
|
|
||||||
then {
|
then {
|
||||||
self.searcher = Some(VecPushSearcher {
|
self.searcher = Some(VecPushSearcher {
|
||||||
found: searcher.found + 1,
|
found: searcher.found + 1,
|
||||||
|
|
|
@ -3,9 +3,7 @@ use std::ops::Range;
|
||||||
|
|
||||||
use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then};
|
use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_ast::ast::{
|
use rustc_ast::ast::{Expr, ExprKind, ImplKind, Item, ItemKind, LitKind, MacCall, StrLit, StrStyle};
|
||||||
Expr, ExprKind, ImplKind, Item, ItemKind, LitKind, MacCall, StrLit, StrStyle,
|
|
||||||
};
|
|
||||||
use rustc_ast::token;
|
use rustc_ast::token;
|
||||||
use rustc_ast::tokenstream::TokenStream;
|
use rustc_ast::tokenstream::TokenStream;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
|
@ -149,7 +147,6 @@ declare_clippy_lint! {
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use std::fmt::Write;
|
/// # use std::fmt::Write;
|
||||||
/// # let mut buf = String::new();
|
/// # let mut buf = String::new();
|
||||||
///
|
|
||||||
/// // Bad
|
/// // Bad
|
||||||
/// writeln!(buf, "");
|
/// writeln!(buf, "");
|
||||||
///
|
///
|
||||||
|
@ -176,7 +173,6 @@ declare_clippy_lint! {
|
||||||
/// # use std::fmt::Write;
|
/// # use std::fmt::Write;
|
||||||
/// # let mut buf = String::new();
|
/// # let mut buf = String::new();
|
||||||
/// # let name = "World";
|
/// # let name = "World";
|
||||||
///
|
|
||||||
/// // Bad
|
/// // Bad
|
||||||
/// write!(buf, "Hello {}!\n", name);
|
/// write!(buf, "Hello {}!\n", name);
|
||||||
///
|
///
|
||||||
|
@ -202,7 +198,6 @@ declare_clippy_lint! {
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use std::fmt::Write;
|
/// # use std::fmt::Write;
|
||||||
/// # let mut buf = String::new();
|
/// # let mut buf = String::new();
|
||||||
///
|
|
||||||
/// // Bad
|
/// // Bad
|
||||||
/// writeln!(buf, "{}", "foo");
|
/// writeln!(buf, "{}", "foo");
|
||||||
///
|
///
|
||||||
|
@ -379,15 +374,10 @@ impl Write {
|
||||||
/// (Some("string to write: {}"), Some(buf))
|
/// (Some("string to write: {}"), Some(buf))
|
||||||
/// ```
|
/// ```
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
fn check_tts<'a>(
|
fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option<StrLit>, Option<Expr>) {
|
||||||
&self,
|
|
||||||
cx: &EarlyContext<'a>,
|
|
||||||
tts: TokenStream,
|
|
||||||
is_write: bool,
|
|
||||||
) -> (Option<StrLit>, Option<Expr>) {
|
|
||||||
use rustc_parse_format::{
|
use rustc_parse_format::{
|
||||||
AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied,
|
AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec, ParseMode, Parser,
|
||||||
FormatSpec, ParseMode, Parser, Piece,
|
Piece,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, false, None);
|
let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, false, None);
|
||||||
|
@ -417,12 +407,7 @@ impl Write {
|
||||||
if let Piece::NextArgument(arg) = piece {
|
if let Piece::NextArgument(arg) = piece {
|
||||||
if !self.in_debug_impl && arg.format.ty == "?" {
|
if !self.in_debug_impl && arg.format.ty == "?" {
|
||||||
// FIXME: modify rustc's fmt string parser to give us the current span
|
// FIXME: modify rustc's fmt string parser to give us the current span
|
||||||
span_lint(
|
span_lint(cx, USE_DEBUG, parser.prev_token.span, "use of `Debug`-based formatting");
|
||||||
cx,
|
|
||||||
USE_DEBUG,
|
|
||||||
parser.prev_token.span,
|
|
||||||
"use of `Debug`-based formatting",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
args.push(arg);
|
args.push(arg);
|
||||||
}
|
}
|
||||||
|
@ -450,9 +435,7 @@ impl Write {
|
||||||
return (Some(fmtstr), None);
|
return (Some(fmtstr), None);
|
||||||
};
|
};
|
||||||
match &token_expr.kind {
|
match &token_expr.kind {
|
||||||
ExprKind::Lit(lit)
|
ExprKind::Lit(lit) if !matches!(lit.kind, LitKind::Int(..) | LitKind::Float(..)) => {
|
||||||
if !matches!(lit.kind, LitKind::Int(..) | LitKind::Float(..)) =>
|
|
||||||
{
|
|
||||||
let mut all_simple = true;
|
let mut all_simple = true;
|
||||||
let mut seen = false;
|
let mut seen = false;
|
||||||
for arg in &args {
|
for arg in &args {
|
||||||
|
@ -462,15 +445,15 @@ impl Write {
|
||||||
all_simple &= arg.format == SIMPLE;
|
all_simple &= arg.format == SIMPLE;
|
||||||
seen = true;
|
seen = true;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
ArgumentNamed(_) => {}
|
ArgumentNamed(_) => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if all_simple && seen {
|
if all_simple && seen {
|
||||||
span_lint(cx, lint, token_expr.span, "literal with an empty format string");
|
span_lint(cx, lint, token_expr.span, "literal with an empty format string");
|
||||||
}
|
}
|
||||||
idx += 1;
|
idx += 1;
|
||||||
}
|
},
|
||||||
ExprKind::Assign(lhs, rhs, _) => {
|
ExprKind::Assign(lhs, rhs, _) => {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let ExprKind::Lit(ref lit) = rhs.kind;
|
if let ExprKind::Lit(ref lit) = rhs.kind;
|
||||||
|
@ -495,7 +478,7 @@ impl Write {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
_ => idx += 1,
|
_ => idx += 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -527,17 +510,11 @@ impl Write {
|
||||||
cx,
|
cx,
|
||||||
PRINT_WITH_NEWLINE,
|
PRINT_WITH_NEWLINE,
|
||||||
mac.span(),
|
mac.span(),
|
||||||
&format!(
|
&format!("using `{}!()` with a format string that ends in a single newline", name),
|
||||||
"using `{}!()` with a format string that ends in a single newline",
|
|
||||||
name
|
|
||||||
),
|
|
||||||
|err| {
|
|err| {
|
||||||
err.multipart_suggestion(
|
err.multipart_suggestion(
|
||||||
&format!("use `{}!` instead", suggested),
|
&format!("use `{}!` instead", suggested),
|
||||||
vec![
|
vec![(mac.path.span, suggested), (newline_span(&fmt_str), String::new())],
|
||||||
(mac.path.span, suggested),
|
|
||||||
(newline_span(&fmt_str), String::new()),
|
|
||||||
],
|
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
19
clippy_utils/Cargo.toml
Normal file
19
clippy_utils/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "clippy_utils"
|
||||||
|
version = "0.1.52"
|
||||||
|
authors = ["The Rust Clippy Developers"]
|
||||||
|
edition = "2018"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
if_chain = "1.0.0"
|
||||||
|
itertools = "0.9"
|
||||||
|
regex-syntax = "0.6"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
smallvec = { version = "1", features = ["union"] }
|
||||||
|
toml = "0.5.3"
|
||||||
|
unicode-normalization = "0.1"
|
||||||
|
rustc-semver="1.1.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
internal-lints = []
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#![allow(clippy::similar_names, clippy::wildcard_imports, clippy::enum_glob_use)]
|
#![allow(clippy::similar_names, clippy::wildcard_imports, clippy::enum_glob_use)]
|
||||||
|
|
||||||
use crate::utils::{both, over};
|
use crate::{both, over};
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::{self as ast, *};
|
use rustc_ast::{self as ast, *};
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
|
@ -229,23 +229,20 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
||||||
match (l, r) {
|
match (l, r) {
|
||||||
(ExternCrate(l), ExternCrate(r)) => l == r,
|
(ExternCrate(l), ExternCrate(r)) => l == r,
|
||||||
(Use(l), Use(r)) => eq_use_tree(l, r),
|
(Use(l), Use(r)) => eq_use_tree(l, r),
|
||||||
(Static(lt, lm, le), Static(rt, rm, re)) => {
|
(Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
|
||||||
lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re)
|
(Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
|
||||||
}
|
|
||||||
(Const(ld, lt, le), Const(rd, rt, re)) => {
|
|
||||||
eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re)
|
|
||||||
}
|
|
||||||
(Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => {
|
(Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => {
|
||||||
eq_defaultness(*ld, *rd)
|
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
|
||||||
&& eq_fn_sig(lf, rf)
|
},
|
||||||
&& eq_generics(lg, rg)
|
(Mod(lu, lmk), Mod(ru, rmk)) => {
|
||||||
&& both(lb, rb, |l, r| eq_block(l, r))
|
lu == ru
|
||||||
}
|
&& match (lmk, rmk) {
|
||||||
(Mod(lu, lmk), Mod(ru, rmk)) => lu == ru && match (lmk, rmk) {
|
(ModKind::Loaded(litems, linline, _), ModKind::Loaded(ritems, rinline, _)) => {
|
||||||
(ModKind::Loaded(litems, linline, _), ModKind::Loaded(ritems, rinline, _)) =>
|
linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind))
|
||||||
linline == rinline && over(litems, ritems, |l, r| eq_item(l, r, eq_item_kind)),
|
},
|
||||||
(ModKind::Unloaded, ModKind::Unloaded) => true,
|
(ModKind::Unloaded, ModKind::Unloaded) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
(ForeignMod(l), ForeignMod(r)) => {
|
(ForeignMod(l), ForeignMod(r)) => {
|
||||||
both(&l.abi, &r.abi, |l, r| eq_str_lit(l, r))
|
both(&l.abi, &r.abi, |l, r| eq_str_lit(l, r))
|
||||||
|
@ -311,15 +308,10 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
||||||
pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
|
pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
|
||||||
use ForeignItemKind::*;
|
use ForeignItemKind::*;
|
||||||
match (l, r) {
|
match (l, r) {
|
||||||
(Static(lt, lm, le), Static(rt, rm, re)) => {
|
(Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
|
||||||
lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re)
|
|
||||||
}
|
|
||||||
(Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => {
|
(Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => {
|
||||||
eq_defaultness(*ld, *rd)
|
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
|
||||||
&& eq_fn_sig(lf, rf)
|
},
|
||||||
&& eq_generics(lg, rg)
|
|
||||||
&& both(lb, rb, |l, r| eq_block(l, r))
|
|
||||||
}
|
|
||||||
(TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
|
(TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
|
||||||
eq_defaultness(*ld, *rd)
|
eq_defaultness(*ld, *rd)
|
||||||
&& eq_generics(lg, rg)
|
&& eq_generics(lg, rg)
|
|
@ -55,6 +55,8 @@ pub fn from(s: &str) -> usize {
|
||||||
}
|
}
|
||||||
} else if c.is_lowercase() {
|
} else if c.is_lowercase() {
|
||||||
down = true;
|
down = true;
|
||||||
|
} else if c.is_uppercase() {
|
||||||
|
last_i = i;
|
||||||
} else {
|
} else {
|
||||||
return last_i;
|
return last_i;
|
||||||
}
|
}
|
||||||
|
@ -70,12 +72,16 @@ mod test {
|
||||||
fn from_full() {
|
fn from_full() {
|
||||||
assert_eq!(from("AbcDef"), 0);
|
assert_eq!(from("AbcDef"), 0);
|
||||||
assert_eq!(from("Abc"), 0);
|
assert_eq!(from("Abc"), 0);
|
||||||
|
assert_eq!(from("ABcd"), 0);
|
||||||
|
assert_eq!(from("ABcdEf"), 0);
|
||||||
|
assert_eq!(from("AabABcd"), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn from_partial() {
|
fn from_partial() {
|
||||||
assert_eq!(from("abcDef"), 3);
|
assert_eq!(from("abcDef"), 3);
|
||||||
assert_eq!(from("aDbc"), 1);
|
assert_eq!(from("aDbc"), 1);
|
||||||
|
assert_eq!(from("aabABcd"), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
574
clippy_utils/src/consts.rs
Normal file
574
clippy_utils/src/consts.rs
Normal file
|
@ -0,0 +1,574 @@
|
||||||
|
#![allow(clippy::float_cmp)]
|
||||||
|
|
||||||
|
use crate::{clip, sext, unsext};
|
||||||
|
use if_chain::if_chain;
|
||||||
|
use rustc_ast::ast::{self, LitFloatType, LitKind};
|
||||||
|
use rustc_data_structures::sync::Lrc;
|
||||||
|
use rustc_hir::def::{DefKind, Res};
|
||||||
|
use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, QPath, UnOp};
|
||||||
|
use rustc_lint::LateContext;
|
||||||
|
use rustc_middle::mir::interpret::Scalar;
|
||||||
|
use rustc_middle::ty::subst::{Subst, SubstsRef};
|
||||||
|
use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty, TyCtxt};
|
||||||
|
use rustc_middle::{bug, span_bug};
|
||||||
|
use rustc_span::symbol::Symbol;
|
||||||
|
use std::cmp::Ordering::{self, Equal};
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
/// A `LitKind`-like enum to fold constant `Expr`s into.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Constant {
|
||||||
|
/// A `String` (e.g., "abc").
|
||||||
|
Str(String),
|
||||||
|
/// A binary string (e.g., `b"abc"`).
|
||||||
|
Binary(Lrc<[u8]>),
|
||||||
|
/// A single `char` (e.g., `'a'`).
|
||||||
|
Char(char),
|
||||||
|
/// An integer's bit representation.
|
||||||
|
Int(u128),
|
||||||
|
/// An `f32`.
|
||||||
|
F32(f32),
|
||||||
|
/// An `f64`.
|
||||||
|
F64(f64),
|
||||||
|
/// `true` or `false`.
|
||||||
|
Bool(bool),
|
||||||
|
/// An array of constants.
|
||||||
|
Vec(Vec<Constant>),
|
||||||
|
/// Also an array, but with only one constant, repeated N times.
|
||||||
|
Repeat(Box<Constant>, u64),
|
||||||
|
/// A tuple of constants.
|
||||||
|
Tuple(Vec<Constant>),
|
||||||
|
/// A raw pointer.
|
||||||
|
RawPtr(u128),
|
||||||
|
/// A reference
|
||||||
|
Ref(Box<Constant>),
|
||||||
|
/// A literal with syntax error.
|
||||||
|
Err(Symbol),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Constant {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(&Self::Str(ref ls), &Self::Str(ref rs)) => ls == rs,
|
||||||
|
(&Self::Binary(ref l), &Self::Binary(ref r)) => l == r,
|
||||||
|
(&Self::Char(l), &Self::Char(r)) => l == r,
|
||||||
|
(&Self::Int(l), &Self::Int(r)) => l == r,
|
||||||
|
(&Self::F64(l), &Self::F64(r)) => {
|
||||||
|
// We want `Fw32 == FwAny` and `FwAny == Fw64`, and by transitivity we must have
|
||||||
|
// `Fw32 == Fw64`, so don’t compare them.
|
||||||
|
// `to_bits` is required to catch non-matching 0.0, -0.0, and NaNs.
|
||||||
|
l.to_bits() == r.to_bits()
|
||||||
|
},
|
||||||
|
(&Self::F32(l), &Self::F32(r)) => {
|
||||||
|
// We want `Fw32 == FwAny` and `FwAny == Fw64`, and by transitivity we must have
|
||||||
|
// `Fw32 == Fw64`, so don’t compare them.
|
||||||
|
// `to_bits` is required to catch non-matching 0.0, -0.0, and NaNs.
|
||||||
|
f64::from(l).to_bits() == f64::from(r).to_bits()
|
||||||
|
},
|
||||||
|
(&Self::Bool(l), &Self::Bool(r)) => l == r,
|
||||||
|
(&Self::Vec(ref l), &Self::Vec(ref r)) | (&Self::Tuple(ref l), &Self::Tuple(ref r)) => l == r,
|
||||||
|
(&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => ls == rs && lv == rv,
|
||||||
|
(&Self::Ref(ref lb), &Self::Ref(ref rb)) => *lb == *rb,
|
||||||
|
// TODO: are there inter-type equalities?
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for Constant {
|
||||||
|
fn hash<H>(&self, state: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
|
std::mem::discriminant(self).hash(state);
|
||||||
|
match *self {
|
||||||
|
Self::Str(ref s) => {
|
||||||
|
s.hash(state);
|
||||||
|
},
|
||||||
|
Self::Binary(ref b) => {
|
||||||
|
b.hash(state);
|
||||||
|
},
|
||||||
|
Self::Char(c) => {
|
||||||
|
c.hash(state);
|
||||||
|
},
|
||||||
|
Self::Int(i) => {
|
||||||
|
i.hash(state);
|
||||||
|
},
|
||||||
|
Self::F32(f) => {
|
||||||
|
f64::from(f).to_bits().hash(state);
|
||||||
|
},
|
||||||
|
Self::F64(f) => {
|
||||||
|
f.to_bits().hash(state);
|
||||||
|
},
|
||||||
|
Self::Bool(b) => {
|
||||||
|
b.hash(state);
|
||||||
|
},
|
||||||
|
Self::Vec(ref v) | Self::Tuple(ref v) => {
|
||||||
|
v.hash(state);
|
||||||
|
},
|
||||||
|
Self::Repeat(ref c, l) => {
|
||||||
|
c.hash(state);
|
||||||
|
l.hash(state);
|
||||||
|
},
|
||||||
|
Self::RawPtr(u) => {
|
||||||
|
u.hash(state);
|
||||||
|
},
|
||||||
|
Self::Ref(ref r) => {
|
||||||
|
r.hash(state);
|
||||||
|
},
|
||||||
|
Self::Err(ref s) => {
|
||||||
|
s.hash(state);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Constant {
|
||||||
|
pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option<Ordering> {
|
||||||
|
match (left, right) {
|
||||||
|
(&Self::Str(ref ls), &Self::Str(ref rs)) => Some(ls.cmp(rs)),
|
||||||
|
(&Self::Char(ref l), &Self::Char(ref r)) => Some(l.cmp(r)),
|
||||||
|
(&Self::Int(l), &Self::Int(r)) => {
|
||||||
|
if let ty::Int(int_ty) = *cmp_type.kind() {
|
||||||
|
Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty)))
|
||||||
|
} else {
|
||||||
|
Some(l.cmp(&r))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(&Self::F64(l), &Self::F64(r)) => l.partial_cmp(&r),
|
||||||
|
(&Self::F32(l), &Self::F32(r)) => l.partial_cmp(&r),
|
||||||
|
(&Self::Bool(ref l), &Self::Bool(ref r)) => Some(l.cmp(r)),
|
||||||
|
(&Self::Tuple(ref l), &Self::Tuple(ref r)) | (&Self::Vec(ref l), &Self::Vec(ref r)) => l
|
||||||
|
.iter()
|
||||||
|
.zip(r.iter())
|
||||||
|
.map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri))
|
||||||
|
.find(|r| r.map_or(true, |o| o != Ordering::Equal))
|
||||||
|
.unwrap_or_else(|| Some(l.len().cmp(&r.len()))),
|
||||||
|
(&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => {
|
||||||
|
match Self::partial_cmp(tcx, cmp_type, lv, rv) {
|
||||||
|
Some(Equal) => Some(ls.cmp(rs)),
|
||||||
|
x => x,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(&Self::Ref(ref lb), &Self::Ref(ref rb)) => Self::partial_cmp(tcx, cmp_type, lb, rb),
|
||||||
|
// TODO: are there any useful inter-type orderings?
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a `LitKind` to a `Constant`.
|
||||||
|
pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
|
||||||
|
match *lit {
|
||||||
|
LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
|
||||||
|
LitKind::Byte(b) => Constant::Int(u128::from(b)),
|
||||||
|
LitKind::ByteStr(ref s) => Constant::Binary(Lrc::clone(s)),
|
||||||
|
LitKind::Char(c) => Constant::Char(c),
|
||||||
|
LitKind::Int(n, _) => Constant::Int(n),
|
||||||
|
LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
|
||||||
|
ast::FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()),
|
||||||
|
ast::FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()),
|
||||||
|
},
|
||||||
|
LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind() {
|
||||||
|
ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
|
||||||
|
ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()),
|
||||||
|
_ => bug!(),
|
||||||
|
},
|
||||||
|
LitKind::Bool(b) => Constant::Bool(b),
|
||||||
|
LitKind::Err(s) => Constant::Err(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn constant<'tcx>(
|
||||||
|
lcx: &LateContext<'tcx>,
|
||||||
|
typeck_results: &ty::TypeckResults<'tcx>,
|
||||||
|
e: &Expr<'_>,
|
||||||
|
) -> Option<(Constant, bool)> {
|
||||||
|
let mut cx = ConstEvalLateContext {
|
||||||
|
lcx,
|
||||||
|
typeck_results,
|
||||||
|
param_env: lcx.param_env,
|
||||||
|
needed_resolution: false,
|
||||||
|
substs: lcx.tcx.intern_substs(&[]),
|
||||||
|
};
|
||||||
|
cx.expr(e).map(|cst| (cst, cx.needed_resolution))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn constant_simple<'tcx>(
|
||||||
|
lcx: &LateContext<'tcx>,
|
||||||
|
typeck_results: &ty::TypeckResults<'tcx>,
|
||||||
|
e: &Expr<'_>,
|
||||||
|
) -> Option<Constant> {
|
||||||
|
constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`.
|
||||||
|
pub fn constant_context<'a, 'tcx>(
|
||||||
|
lcx: &'a LateContext<'tcx>,
|
||||||
|
typeck_results: &'a ty::TypeckResults<'tcx>,
|
||||||
|
) -> ConstEvalLateContext<'a, 'tcx> {
|
||||||
|
ConstEvalLateContext {
|
||||||
|
lcx,
|
||||||
|
typeck_results,
|
||||||
|
param_env: lcx.param_env,
|
||||||
|
needed_resolution: false,
|
||||||
|
substs: lcx.tcx.intern_substs(&[]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ConstEvalLateContext<'a, 'tcx> {
|
||||||
|
lcx: &'a LateContext<'tcx>,
|
||||||
|
typeck_results: &'a ty::TypeckResults<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
needed_resolution: bool,
|
||||||
|
substs: SubstsRef<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||||
|
/// Simple constant folding: Insert an expression, get a constant or none.
|
||||||
|
pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
|
||||||
|
match e.kind {
|
||||||
|
ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
|
||||||
|
ExprKind::Block(ref block, _) => self.block(block),
|
||||||
|
ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))),
|
||||||
|
ExprKind::Array(ref vec) => self.multi(vec).map(Constant::Vec),
|
||||||
|
ExprKind::Tup(ref tup) => self.multi(tup).map(Constant::Tuple),
|
||||||
|
ExprKind::Repeat(ref value, _) => {
|
||||||
|
let n = match self.typeck_results.expr_ty(e).kind() {
|
||||||
|
ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?,
|
||||||
|
_ => span_bug!(e.span, "typeck error"),
|
||||||
|
};
|
||||||
|
self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
|
||||||
|
},
|
||||||
|
ExprKind::Unary(op, ref operand) => self.expr(operand).and_then(|o| match op {
|
||||||
|
UnOp::Not => self.constant_not(&o, self.typeck_results.expr_ty(e)),
|
||||||
|
UnOp::Neg => self.constant_negate(&o, self.typeck_results.expr_ty(e)),
|
||||||
|
UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }),
|
||||||
|
}),
|
||||||
|
ExprKind::If(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
|
||||||
|
ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right),
|
||||||
|
ExprKind::Call(ref callee, ref args) => {
|
||||||
|
// We only handle a few const functions for now.
|
||||||
|
if_chain! {
|
||||||
|
if args.is_empty();
|
||||||
|
if let ExprKind::Path(qpath) = &callee.kind;
|
||||||
|
let res = self.typeck_results.qpath_res(qpath, callee.hir_id);
|
||||||
|
if let Some(def_id) = res.opt_def_id();
|
||||||
|
let def_path: Vec<_> = self.lcx.get_def_path(def_id).into_iter().map(Symbol::as_str).collect();
|
||||||
|
let def_path: Vec<&str> = def_path.iter().take(4).map(|s| &**s).collect();
|
||||||
|
if let ["core", "num", int_impl, "max_value"] = *def_path;
|
||||||
|
then {
|
||||||
|
let value = match int_impl {
|
||||||
|
"<impl i8>" => i8::MAX as u128,
|
||||||
|
"<impl i16>" => i16::MAX as u128,
|
||||||
|
"<impl i32>" => i32::MAX as u128,
|
||||||
|
"<impl i64>" => i64::MAX as u128,
|
||||||
|
"<impl i128>" => i128::MAX as u128,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
Some(Constant::Int(value))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ExprKind::Index(ref arr, ref index) => self.index(arr, index),
|
||||||
|
ExprKind::AddrOf(_, _, ref inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
|
||||||
|
// TODO: add other expressions.
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_wrap)]
|
||||||
|
fn constant_not(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
|
||||||
|
use self::Constant::{Bool, Int};
|
||||||
|
match *o {
|
||||||
|
Bool(b) => Some(Bool(!b)),
|
||||||
|
Int(value) => {
|
||||||
|
let value = !value;
|
||||||
|
match *ty.kind() {
|
||||||
|
ty::Int(ity) => Some(Int(unsext(self.lcx.tcx, value as i128, ity))),
|
||||||
|
ty::Uint(ity) => Some(Int(clip(self.lcx.tcx, value, ity))),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constant_negate(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
|
||||||
|
use self::Constant::{Int, F32, F64};
|
||||||
|
match *o {
|
||||||
|
Int(value) => {
|
||||||
|
let ity = match *ty.kind() {
|
||||||
|
ty::Int(ity) => ity,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
// sign extend
|
||||||
|
let value = sext(self.lcx.tcx, value, ity);
|
||||||
|
let value = value.checked_neg()?;
|
||||||
|
// clear unused bits
|
||||||
|
Some(Int(unsext(self.lcx.tcx, value, ity)))
|
||||||
|
},
|
||||||
|
F32(f) => Some(F32(-f)),
|
||||||
|
F64(f) => Some(F64(-f)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create `Some(Vec![..])` of all constants, unless there is any
|
||||||
|
/// non-constant part.
|
||||||
|
fn multi(&mut self, vec: &[Expr<'_>]) -> Option<Vec<Constant>> {
|
||||||
|
vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lookup a possibly constant expression from a `ExprKind::Path`.
|
||||||
|
fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<Constant> {
|
||||||
|
let res = self.typeck_results.qpath_res(qpath, id);
|
||||||
|
match res {
|
||||||
|
Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
|
||||||
|
let substs = self.typeck_results.node_substs(id);
|
||||||
|
let substs = if self.substs.is_empty() {
|
||||||
|
substs
|
||||||
|
} else {
|
||||||
|
substs.subst(self.lcx.tcx, self.substs)
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = self
|
||||||
|
.lcx
|
||||||
|
.tcx
|
||||||
|
.const_eval_resolve(
|
||||||
|
self.param_env,
|
||||||
|
ty::WithOptConstParam::unknown(def_id),
|
||||||
|
substs,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.ok()
|
||||||
|
.map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
|
||||||
|
let result = miri_to_const(&result);
|
||||||
|
if result.is_some() {
|
||||||
|
self.needed_resolution = true;
|
||||||
|
}
|
||||||
|
result
|
||||||
|
},
|
||||||
|
// FIXME: cover all usable cases.
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant> {
|
||||||
|
let lhs = self.expr(lhs);
|
||||||
|
let index = self.expr(index);
|
||||||
|
|
||||||
|
match (lhs, index) {
|
||||||
|
(Some(Constant::Vec(vec)), Some(Constant::Int(index))) => match vec.get(index as usize) {
|
||||||
|
Some(Constant::F32(x)) => Some(Constant::F32(*x)),
|
||||||
|
Some(Constant::F64(x)) => Some(Constant::F64(*x)),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
(Some(Constant::Vec(vec)), _) => {
|
||||||
|
if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) {
|
||||||
|
match vec.get(0) {
|
||||||
|
Some(Constant::F32(x)) => Some(Constant::F32(*x)),
|
||||||
|
Some(Constant::F64(x)) => Some(Constant::F64(*x)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A block can only yield a constant if it only has one constant expression.
|
||||||
|
fn block(&mut self, block: &Block<'_>) -> Option<Constant> {
|
||||||
|
if block.stmts.is_empty() {
|
||||||
|
block.expr.as_ref().and_then(|b| self.expr(b))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant> {
|
||||||
|
if let Some(Constant::Bool(b)) = self.expr(cond) {
|
||||||
|
if b {
|
||||||
|
self.expr(&*then)
|
||||||
|
} else {
|
||||||
|
otherwise.as_ref().and_then(|expr| self.expr(expr))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant> {
|
||||||
|
let l = self.expr(left)?;
|
||||||
|
let r = self.expr(right);
|
||||||
|
match (l, r) {
|
||||||
|
(Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck_results.expr_ty_opt(left)?.kind() {
|
||||||
|
ty::Int(ity) => {
|
||||||
|
let l = sext(self.lcx.tcx, l, ity);
|
||||||
|
let r = sext(self.lcx.tcx, r, ity);
|
||||||
|
let zext = |n: i128| Constant::Int(unsext(self.lcx.tcx, n, ity));
|
||||||
|
match op.node {
|
||||||
|
BinOpKind::Add => l.checked_add(r).map(zext),
|
||||||
|
BinOpKind::Sub => l.checked_sub(r).map(zext),
|
||||||
|
BinOpKind::Mul => l.checked_mul(r).map(zext),
|
||||||
|
BinOpKind::Div if r != 0 => l.checked_div(r).map(zext),
|
||||||
|
BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext),
|
||||||
|
BinOpKind::Shr => l.checked_shr(r.try_into().expect("invalid shift")).map(zext),
|
||||||
|
BinOpKind::Shl => l.checked_shl(r.try_into().expect("invalid shift")).map(zext),
|
||||||
|
BinOpKind::BitXor => Some(zext(l ^ r)),
|
||||||
|
BinOpKind::BitOr => Some(zext(l | r)),
|
||||||
|
BinOpKind::BitAnd => Some(zext(l & r)),
|
||||||
|
BinOpKind::Eq => Some(Constant::Bool(l == r)),
|
||||||
|
BinOpKind::Ne => Some(Constant::Bool(l != r)),
|
||||||
|
BinOpKind::Lt => Some(Constant::Bool(l < r)),
|
||||||
|
BinOpKind::Le => Some(Constant::Bool(l <= r)),
|
||||||
|
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
|
||||||
|
BinOpKind::Gt => Some(Constant::Bool(l > r)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ty::Uint(_) => match op.node {
|
||||||
|
BinOpKind::Add => l.checked_add(r).map(Constant::Int),
|
||||||
|
BinOpKind::Sub => l.checked_sub(r).map(Constant::Int),
|
||||||
|
BinOpKind::Mul => l.checked_mul(r).map(Constant::Int),
|
||||||
|
BinOpKind::Div => l.checked_div(r).map(Constant::Int),
|
||||||
|
BinOpKind::Rem => l.checked_rem(r).map(Constant::Int),
|
||||||
|
BinOpKind::Shr => l.checked_shr(r.try_into().expect("shift too large")).map(Constant::Int),
|
||||||
|
BinOpKind::Shl => l.checked_shl(r.try_into().expect("shift too large")).map(Constant::Int),
|
||||||
|
BinOpKind::BitXor => Some(Constant::Int(l ^ r)),
|
||||||
|
BinOpKind::BitOr => Some(Constant::Int(l | r)),
|
||||||
|
BinOpKind::BitAnd => Some(Constant::Int(l & r)),
|
||||||
|
BinOpKind::Eq => Some(Constant::Bool(l == r)),
|
||||||
|
BinOpKind::Ne => Some(Constant::Bool(l != r)),
|
||||||
|
BinOpKind::Lt => Some(Constant::Bool(l < r)),
|
||||||
|
BinOpKind::Le => Some(Constant::Bool(l <= r)),
|
||||||
|
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
|
||||||
|
BinOpKind::Gt => Some(Constant::Bool(l > r)),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
(Constant::F32(l), Some(Constant::F32(r))) => match op.node {
|
||||||
|
BinOpKind::Add => Some(Constant::F32(l + r)),
|
||||||
|
BinOpKind::Sub => Some(Constant::F32(l - r)),
|
||||||
|
BinOpKind::Mul => Some(Constant::F32(l * r)),
|
||||||
|
BinOpKind::Div => Some(Constant::F32(l / r)),
|
||||||
|
BinOpKind::Rem => Some(Constant::F32(l % r)),
|
||||||
|
BinOpKind::Eq => Some(Constant::Bool(l == r)),
|
||||||
|
BinOpKind::Ne => Some(Constant::Bool(l != r)),
|
||||||
|
BinOpKind::Lt => Some(Constant::Bool(l < r)),
|
||||||
|
BinOpKind::Le => Some(Constant::Bool(l <= r)),
|
||||||
|
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
|
||||||
|
BinOpKind::Gt => Some(Constant::Bool(l > r)),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
(Constant::F64(l), Some(Constant::F64(r))) => match op.node {
|
||||||
|
BinOpKind::Add => Some(Constant::F64(l + r)),
|
||||||
|
BinOpKind::Sub => Some(Constant::F64(l - r)),
|
||||||
|
BinOpKind::Mul => Some(Constant::F64(l * r)),
|
||||||
|
BinOpKind::Div => Some(Constant::F64(l / r)),
|
||||||
|
BinOpKind::Rem => Some(Constant::F64(l % r)),
|
||||||
|
BinOpKind::Eq => Some(Constant::Bool(l == r)),
|
||||||
|
BinOpKind::Ne => Some(Constant::Bool(l != r)),
|
||||||
|
BinOpKind::Lt => Some(Constant::Bool(l < r)),
|
||||||
|
BinOpKind::Le => Some(Constant::Bool(l <= r)),
|
||||||
|
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
|
||||||
|
BinOpKind::Gt => Some(Constant::Bool(l > r)),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
(l, r) => match (op.node, l, r) {
|
||||||
|
(BinOpKind::And, Constant::Bool(false), _) => Some(Constant::Bool(false)),
|
||||||
|
(BinOpKind::Or, Constant::Bool(true), _) => Some(Constant::Bool(true)),
|
||||||
|
(BinOpKind::And, Constant::Bool(true), Some(r)) | (BinOpKind::Or, Constant::Bool(false), Some(r)) => {
|
||||||
|
Some(r)
|
||||||
|
},
|
||||||
|
(BinOpKind::BitXor, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l ^ r)),
|
||||||
|
(BinOpKind::BitAnd, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l & r)),
|
||||||
|
(BinOpKind::BitOr, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l | r)),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
|
||||||
|
use rustc_middle::mir::interpret::ConstValue;
|
||||||
|
match result.val {
|
||||||
|
ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(int))) => {
|
||||||
|
match result.ty.kind() {
|
||||||
|
ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
|
||||||
|
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
|
||||||
|
ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
|
||||||
|
int.try_into().expect("invalid f32 bit representation"),
|
||||||
|
))),
|
||||||
|
ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
|
||||||
|
int.try_into().expect("invalid f64 bit representation"),
|
||||||
|
))),
|
||||||
|
ty::RawPtr(type_and_mut) => {
|
||||||
|
if let ty::Uint(_) = type_and_mut.ty.kind() {
|
||||||
|
return Some(Constant::RawPtr(int.assert_bits(int.size())));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
},
|
||||||
|
// FIXME: implement other conversions.
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind() {
|
||||||
|
ty::Ref(_, tam, _) => match tam.kind() {
|
||||||
|
ty::Str => String::from_utf8(
|
||||||
|
data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.ok()
|
||||||
|
.map(Constant::Str),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind() {
|
||||||
|
ty::Array(sub_type, len) => match sub_type.kind() {
|
||||||
|
ty::Float(FloatTy::F32) => match miri_to_const(len) {
|
||||||
|
Some(Constant::Int(len)) => alloc
|
||||||
|
.inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
|
||||||
|
.to_owned()
|
||||||
|
.chunks(4)
|
||||||
|
.map(|chunk| {
|
||||||
|
Some(Constant::F32(f32::from_le_bytes(
|
||||||
|
chunk.try_into().expect("this shouldn't happen"),
|
||||||
|
)))
|
||||||
|
})
|
||||||
|
.collect::<Option<Vec<Constant>>>()
|
||||||
|
.map(Constant::Vec),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
ty::Float(FloatTy::F64) => match miri_to_const(len) {
|
||||||
|
Some(Constant::Int(len)) => alloc
|
||||||
|
.inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize))
|
||||||
|
.to_owned()
|
||||||
|
.chunks(8)
|
||||||
|
.map(|chunk| {
|
||||||
|
Some(Constant::F64(f64::from_le_bytes(
|
||||||
|
chunk.try_into().expect("this shouldn't happen"),
|
||||||
|
)))
|
||||||
|
})
|
||||||
|
.collect::<Option<Vec<Constant>>>()
|
||||||
|
.map(Constant::Vec),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
// FIXME: implement other array type conversions.
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
// FIXME: implement other conversions.
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@
|
||||||
//! - or-fun-call
|
//! - or-fun-call
|
||||||
//! - option-if-let-else
|
//! - option-if-let-else
|
||||||
|
|
||||||
use crate::utils::{is_ctor_or_promotable_const_function, is_type_diagnostic_item, match_type, paths};
|
use crate::{is_ctor_or_promotable_const_function, is_type_diagnostic_item, match_type, paths};
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
|
|
||||||
use rustc_hir::intravisit;
|
use rustc_hir::intravisit;
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#![deny(clippy::missing_docs_in_private_items)]
|
#![deny(clippy::missing_docs_in_private_items)]
|
||||||
|
|
||||||
use crate::utils::{is_expn_of, match_def_path, paths};
|
use crate::{is_expn_of, match_def_path, paths};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_ast::ast;
|
use rustc_ast::ast;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
|
@ -1,10 +1,12 @@
|
||||||
use crate::consts::{constant_context, constant_simple};
|
use crate::consts::{constant_context, constant_simple};
|
||||||
use crate::utils::differing_macro_contexts;
|
use crate::differing_macro_contexts;
|
||||||
use rustc_ast::ast::InlineAsmTemplatePiece;
|
use rustc_ast::ast::InlineAsmTemplatePiece;
|
||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
|
use rustc_hir::def::Res;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FieldPat, FnRetTy,
|
BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FieldPat, FnRetTy,
|
||||||
GenericArg, GenericArgs, Guard, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatKind, Path,
|
GenericArg, GenericArgs, Guard, HirId, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatKind, Path,
|
||||||
PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
|
PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
|
||||||
};
|
};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
|
@ -24,7 +26,7 @@ pub struct SpanlessEq<'a, 'tcx> {
|
||||||
cx: &'a LateContext<'tcx>,
|
cx: &'a LateContext<'tcx>,
|
||||||
maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
|
maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
|
||||||
allow_side_effects: bool,
|
allow_side_effects: bool,
|
||||||
expr_fallback: Option<Box<dyn Fn(&Expr<'_>, &Expr<'_>) -> bool + 'a>>,
|
expr_fallback: Option<Box<dyn FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
|
@ -45,15 +47,54 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr_fallback(self, expr_fallback: impl Fn(&Expr<'_>, &Expr<'_>) -> bool + 'a) -> Self {
|
pub fn expr_fallback(self, expr_fallback: impl FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a) -> Self {
|
||||||
Self {
|
Self {
|
||||||
expr_fallback: Some(Box::new(expr_fallback)),
|
expr_fallback: Some(Box::new(expr_fallback)),
|
||||||
..self
|
..self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks whether two statements are the same.
|
/// Use this method to wrap comparisons that may involve inter-expression context.
|
||||||
pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
|
/// See `self.locals`.
|
||||||
|
fn inter_expr(&mut self) -> HirEqInterExpr<'_, 'a, 'tcx> {
|
||||||
|
HirEqInterExpr {
|
||||||
|
inner: self,
|
||||||
|
locals: FxHashMap::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
|
||||||
|
self.inter_expr().eq_block(left, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
|
||||||
|
self.inter_expr().eq_expr(left, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eq_path_segment(&mut self, left: &PathSegment<'_>, right: &PathSegment<'_>) -> bool {
|
||||||
|
self.inter_expr().eq_path_segment(left, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eq_path_segments(&mut self, left: &[PathSegment<'_>], right: &[PathSegment<'_>]) -> bool {
|
||||||
|
self.inter_expr().eq_path_segments(left, right)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eq_ty_kind(&mut self, left: &TyKind<'_>, right: &TyKind<'_>) -> bool {
|
||||||
|
self.inter_expr().eq_ty_kind(left, right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HirEqInterExpr<'a, 'b, 'tcx> {
|
||||||
|
inner: &'a mut SpanlessEq<'b, 'tcx>,
|
||||||
|
|
||||||
|
// When binding are declared, the binding ID in the left expression is mapped to the one on the
|
||||||
|
// right. For example, when comparing `{ let x = 1; x + 2 }` and `{ let y = 1; y + 2 }`,
|
||||||
|
// these blocks are considered equal since `x` is mapped to `y`.
|
||||||
|
locals: FxHashMap<HirId, HirId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HirEqInterExpr<'_, '_, '_> {
|
||||||
|
fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
|
||||||
match (&left.kind, &right.kind) {
|
match (&left.kind, &right.kind) {
|
||||||
(&StmtKind::Local(ref l), &StmtKind::Local(ref r)) => {
|
(&StmtKind::Local(ref l), &StmtKind::Local(ref r)) => {
|
||||||
self.eq_pat(&l.pat, &r.pat)
|
self.eq_pat(&l.pat, &r.pat)
|
||||||
|
@ -68,21 +109,21 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks whether two blocks are the same.
|
/// Checks whether two blocks are the same.
|
||||||
pub fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
|
fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
|
||||||
over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r))
|
over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r))
|
||||||
&& both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
|
&& both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::similar_names)]
|
#[allow(clippy::similar_names)]
|
||||||
pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
|
fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
|
||||||
if !self.allow_side_effects && differing_macro_contexts(left.span, right.span) {
|
if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(typeck_results) = self.maybe_typeck_results {
|
if let Some(typeck_results) = self.inner.maybe_typeck_results {
|
||||||
if let (Some(l), Some(r)) = (
|
if let (Some(l), Some(r)) = (
|
||||||
constant_simple(self.cx, typeck_results, left),
|
constant_simple(self.inner.cx, typeck_results, left),
|
||||||
constant_simple(self.cx, typeck_results, right),
|
constant_simple(self.inner.cx, typeck_results, right),
|
||||||
) {
|
) {
|
||||||
if l == r {
|
if l == r {
|
||||||
return true;
|
return true;
|
||||||
|
@ -98,10 +139,10 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
|
both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
|
||||||
},
|
},
|
||||||
(&ExprKind::Assign(ref ll, ref lr, _), &ExprKind::Assign(ref rl, ref rr, _)) => {
|
(&ExprKind::Assign(ref ll, ref lr, _), &ExprKind::Assign(ref rl, ref rr, _)) => {
|
||||||
self.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
|
self.inner.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
|
||||||
},
|
},
|
||||||
(&ExprKind::AssignOp(ref lo, ref ll, ref lr), &ExprKind::AssignOp(ref ro, ref rl, ref rr)) => {
|
(&ExprKind::AssignOp(ref lo, ref ll, ref lr), &ExprKind::AssignOp(ref ro, ref rl, ref rr)) => {
|
||||||
self.allow_side_effects && lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
|
self.inner.allow_side_effects && lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
|
||||||
},
|
},
|
||||||
(&ExprKind::Block(ref l, _), &ExprKind::Block(ref r, _)) => self.eq_block(l, r),
|
(&ExprKind::Block(ref l, _), &ExprKind::Block(ref r, _)) => self.eq_block(l, r),
|
||||||
(&ExprKind::Binary(l_op, ref ll, ref lr), &ExprKind::Binary(r_op, ref rl, ref rr)) => {
|
(&ExprKind::Binary(l_op, ref ll, ref lr), &ExprKind::Binary(r_op, ref rl, ref rr)) => {
|
||||||
|
@ -116,7 +157,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
},
|
},
|
||||||
(&ExprKind::Box(ref l), &ExprKind::Box(ref r)) => self.eq_expr(l, r),
|
(&ExprKind::Box(ref l), &ExprKind::Box(ref r)) => self.eq_expr(l, r),
|
||||||
(&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => {
|
(&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => {
|
||||||
self.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
|
self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
|
||||||
},
|
},
|
||||||
(&ExprKind::Cast(ref lx, ref lt), &ExprKind::Cast(ref rx, ref rt))
|
(&ExprKind::Cast(ref lx, ref lt), &ExprKind::Cast(ref rx, ref rt))
|
||||||
| (&ExprKind::Type(ref lx, ref lt), &ExprKind::Type(ref rx, ref rt)) => {
|
| (&ExprKind::Type(ref lx, ref lt), &ExprKind::Type(ref rx, ref rt)) => {
|
||||||
|
@ -139,19 +180,19 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
ls == rs
|
ls == rs
|
||||||
&& self.eq_expr(le, re)
|
&& self.eq_expr(le, re)
|
||||||
&& over(la, ra, |l, r| {
|
&& over(la, ra, |l, r| {
|
||||||
self.eq_expr(&l.body, &r.body)
|
self.eq_pat(&l.pat, &r.pat)
|
||||||
&& both(&l.guard, &r.guard, |l, r| self.eq_guard(l, r))
|
&& both(&l.guard, &r.guard, |l, r| self.eq_guard(l, r))
|
||||||
&& self.eq_pat(&l.pat, &r.pat)
|
&& self.eq_expr(&l.body, &r.body)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
(&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => {
|
(&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => {
|
||||||
self.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
|
self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
|
||||||
},
|
},
|
||||||
(&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => {
|
(&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => {
|
||||||
let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(ll_id.body));
|
let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(ll_id.body));
|
||||||
let ll = celcx.expr(&self.cx.tcx.hir().body(ll_id.body).value);
|
let ll = celcx.expr(&self.inner.cx.tcx.hir().body(ll_id.body).value);
|
||||||
let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(rl_id.body));
|
let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(rl_id.body));
|
||||||
let rl = celcx.expr(&self.cx.tcx.hir().body(rl_id.body).value);
|
let rl = celcx.expr(&self.inner.cx.tcx.hir().body(rl_id.body).value);
|
||||||
|
|
||||||
self.eq_expr(le, re) && ll == rl
|
self.eq_expr(le, re) && ll == rl
|
||||||
},
|
},
|
||||||
|
@ -168,7 +209,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
(&ExprKind::DropTemps(ref le), &ExprKind::DropTemps(ref re)) => self.eq_expr(le, re),
|
(&ExprKind::DropTemps(ref le), &ExprKind::DropTemps(ref re)) => self.eq_expr(le, re),
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
is_eq || self.expr_fallback.as_ref().map_or(false, |f| f(left, right))
|
is_eq || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool {
|
fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool {
|
||||||
|
@ -199,13 +240,13 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
left.name == right.name
|
left.name == right.name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eq_fieldpat(&mut self, left: &FieldPat<'_>, right: &FieldPat<'_>) -> bool {
|
fn eq_fieldpat(&mut self, left: &FieldPat<'_>, right: &FieldPat<'_>) -> bool {
|
||||||
let (FieldPat { ident: li, pat: lp, .. }, FieldPat { ident: ri, pat: rp, .. }) = (&left, &right);
|
let (FieldPat { ident: li, pat: lp, .. }, FieldPat { ident: ri, pat: rp, .. }) = (&left, &right);
|
||||||
li.name == ri.name && self.eq_pat(lp, rp)
|
li.name == ri.name && self.eq_pat(lp, rp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks whether two patterns are the same.
|
/// Checks whether two patterns are the same.
|
||||||
pub fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
|
fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
|
||||||
match (&left.kind, &right.kind) {
|
match (&left.kind, &right.kind) {
|
||||||
(&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
|
(&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
|
||||||
(&PatKind::Struct(ref lp, ref la, ..), &PatKind::Struct(ref rp, ref ra, ..)) => {
|
(&PatKind::Struct(ref lp, ref la, ..), &PatKind::Struct(ref rp, ref ra, ..)) => {
|
||||||
|
@ -214,8 +255,12 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
(&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
|
(&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
|
||||||
self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
|
self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
|
||||||
},
|
},
|
||||||
(&PatKind::Binding(ref lb, .., ref li, ref lp), &PatKind::Binding(ref rb, .., ref ri, ref rp)) => {
|
(&PatKind::Binding(lb, li, _, ref lp), &PatKind::Binding(rb, ri, _, ref rp)) => {
|
||||||
lb == rb && li.name == ri.name && both(lp, rp, |l, r| self.eq_pat(l, r))
|
let eq = lb == rb && both(lp, rp, |l, r| self.eq_pat(l, r));
|
||||||
|
if eq {
|
||||||
|
self.locals.insert(li, ri);
|
||||||
|
}
|
||||||
|
eq
|
||||||
},
|
},
|
||||||
(&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r),
|
(&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r),
|
||||||
(&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r),
|
(&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r),
|
||||||
|
@ -251,8 +296,11 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eq_path(&mut self, left: &Path<'_>, right: &Path<'_>) -> bool {
|
fn eq_path(&mut self, left: &Path<'_>, right: &Path<'_>) -> bool {
|
||||||
left.is_global() == right.is_global()
|
match (left.res, right.res) {
|
||||||
&& over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r))
|
(Res::Local(l), Res::Local(r)) => l == r || self.locals.get(&l) == Some(&r),
|
||||||
|
(Res::Local(_), _) | (_, Res::Local(_)) => false,
|
||||||
|
_ => over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool {
|
fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool {
|
||||||
|
@ -279,28 +327,19 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
left.ident.name == right.ident.name && both(&left.args, &right.args, |l, r| self.eq_path_parameters(l, r))
|
left.ident.name == right.ident.name && both(&left.args, &right.args, |l, r| self.eq_path_parameters(l, r))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
|
fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
|
||||||
self.eq_ty_kind(&left.kind, &right.kind)
|
self.eq_ty_kind(&left.kind, &right.kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::similar_names)]
|
#[allow(clippy::similar_names)]
|
||||||
pub fn eq_ty_kind(&mut self, left: &TyKind<'_>, right: &TyKind<'_>) -> bool {
|
fn eq_ty_kind(&mut self, left: &TyKind<'_>, right: &TyKind<'_>) -> bool {
|
||||||
match (left, right) {
|
match (left, right) {
|
||||||
(&TyKind::Slice(ref l_vec), &TyKind::Slice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
|
(&TyKind::Slice(ref l_vec), &TyKind::Slice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
|
||||||
(&TyKind::Array(ref lt, ref ll_id), &TyKind::Array(ref rt, ref rl_id)) => {
|
(&TyKind::Array(ref lt, ref ll_id), &TyKind::Array(ref rt, ref rl_id)) => {
|
||||||
let old_maybe_typeck_results = self.maybe_typeck_results;
|
let cx = self.inner.cx;
|
||||||
|
let eval_const =
|
||||||
let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(ll_id.body));
|
|body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
|
||||||
self.maybe_typeck_results = Some(self.cx.tcx.typeck_body(ll_id.body));
|
self.eq_ty(lt, rt) && eval_const(ll_id.body) == eval_const(rl_id.body)
|
||||||
let ll = celcx.expr(&self.cx.tcx.hir().body(ll_id.body).value);
|
|
||||||
|
|
||||||
let mut celcx = constant_context(self.cx, self.cx.tcx.typeck_body(rl_id.body));
|
|
||||||
self.maybe_typeck_results = Some(self.cx.tcx.typeck_body(rl_id.body));
|
|
||||||
let rl = celcx.expr(&self.cx.tcx.hir().body(rl_id.body).value);
|
|
||||||
|
|
||||||
let eq_ty = self.eq_ty(lt, rt);
|
|
||||||
self.maybe_typeck_results = old_maybe_typeck_results;
|
|
||||||
eq_ty && ll == rl
|
|
||||||
},
|
},
|
||||||
(&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
|
(&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
|
||||||
l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
|
l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
|
||||||
|
@ -667,10 +706,15 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||||
// self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
|
// self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash_path(&mut self, p: &Path<'_>) {
|
pub fn hash_path(&mut self, path: &Path<'_>) {
|
||||||
p.is_global().hash(&mut self.s);
|
match path.res {
|
||||||
for p in p.segments {
|
// constant hash since equality is dependant on inter-expression context
|
||||||
self.hash_name(p.ident.name);
|
Res::Local(_) => 1_usize.hash(&mut self.s),
|
||||||
|
_ => {
|
||||||
|
for seg in path.segments {
|
||||||
|
self.hash_name(seg.ident.name);
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1884
clippy_utils/src/lib.rs
Normal file
1884
clippy_utils/src/lib.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
||||||
use crate::utils::{get_pat_name, match_var, snippet};
|
use crate::{get_pat_name, match_var, snippet};
|
||||||
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
||||||
use rustc_hir::{Body, BodyId, Expr, ExprKind, Param};
|
use rustc_hir::{Body, BodyId, Expr, ExprKind, Param};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
|
@ -1,7 +1,7 @@
|
||||||
//! Contains utility functions to generate suggestions.
|
//! Contains utility functions to generate suggestions.
|
||||||
#![deny(clippy::missing_docs_in_private_items)]
|
#![deny(clippy::missing_docs_in_private_items)]
|
||||||
|
|
||||||
use crate::utils::{higher, snippet, snippet_opt, snippet_with_macro_callsite};
|
use crate::{higher, snippet, snippet_opt, snippet_with_macro_callsite};
|
||||||
use rustc_ast::util::parser::AssocOp;
|
use rustc_ast::util::parser::AssocOp;
|
||||||
use rustc_ast::{ast, token};
|
use rustc_ast::{ast, token};
|
||||||
use rustc_ast_pretty::pprust::token_kind_to_string;
|
use rustc_ast_pretty::pprust::token_kind_to_string;
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::utils;
|
use crate as utils;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::utils::path_to_local_id;
|
use crate::path_to_local_id;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::intravisit::{self, walk_expr, NestedVisitorMap, Visitor};
|
use rustc_hir::intravisit::{self, walk_expr, NestedVisitorMap, Visitor};
|
||||||
use rustc_hir::{Arm, Body, Expr, HirId, Stmt};
|
use rustc_hir::{Arm, Body, Expr, HirId, Stmt};
|
|
@ -108,6 +108,9 @@ should only commit files changed by `cargo dev bless` for the
|
||||||
specific lint you are creating/editing. Note that if the generated files are
|
specific lint you are creating/editing. Note that if the generated files are
|
||||||
empty, they should be removed.
|
empty, they should be removed.
|
||||||
|
|
||||||
|
Note that you can run multiple test files by specifying a comma separated list:
|
||||||
|
`TESTNAME=foo_functions,test2,test3`.
|
||||||
|
|
||||||
### Cargo lints
|
### Cargo lints
|
||||||
|
|
||||||
For cargo lints, the process of testing differs in that we are interested in
|
For cargo lints, the process of testing differs in that we are interested in
|
||||||
|
@ -289,7 +292,7 @@ the next section. Let's worry about the details later and emit our lint for
|
||||||
|
|
||||||
Depending on how complex we want our lint message to be, we can choose from a
|
Depending on how complex we want our lint message to be, we can choose from a
|
||||||
variety of lint emission functions. They can all be found in
|
variety of lint emission functions. They can all be found in
|
||||||
[`clippy_lints/src/utils/diagnostics.rs`][diagnostics].
|
[`clippy_utils/src/diagnostics.rs`][diagnostics].
|
||||||
|
|
||||||
`span_lint_and_help` seems most appropriate in this case. It allows us to
|
`span_lint_and_help` seems most appropriate in this case. It allows us to
|
||||||
provide an extra help message and we can't really suggest a better name
|
provide an extra help message and we can't really suggest a better name
|
||||||
|
@ -318,7 +321,7 @@ When code or an identifier must appear in a message or label, it should be
|
||||||
surrounded with single grave accents \`.
|
surrounded with single grave accents \`.
|
||||||
|
|
||||||
[check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html#method.check_fn
|
[check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html#method.check_fn
|
||||||
[diagnostics]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/diagnostics.rs
|
[diagnostics]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_utils/src/diagnostics.rs
|
||||||
[the rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/diagnostics.html
|
[the rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/diagnostics.html
|
||||||
|
|
||||||
## Adding the lint logic
|
## Adding the lint logic
|
||||||
|
@ -534,7 +537,7 @@ directory. Adding a configuration to a lint can be useful for thresholds or to c
|
||||||
behavior that can be seen as a false positive for some users. Adding a configuration is done
|
behavior that can be seen as a false positive for some users. Adding a configuration is done
|
||||||
in the following steps:
|
in the following steps:
|
||||||
|
|
||||||
1. Adding a new configuration entry to [clippy_lints::utils::conf](/clippy_lints/src/utils/conf.rs)
|
1. Adding a new configuration entry to [clippy_utils::conf](/clippy_utils/src/conf.rs)
|
||||||
like this:
|
like this:
|
||||||
```rust
|
```rust
|
||||||
/// Lint: LINT_NAME. <The configuration field doc comment>
|
/// Lint: LINT_NAME. <The configuration field doc comment>
|
||||||
|
@ -633,7 +636,7 @@ documentation currently. This is unfortunate, but in most cases you can probably
|
||||||
get away with copying things from existing similar lints. If you are stuck,
|
get away with copying things from existing similar lints. If you are stuck,
|
||||||
don't hesitate to ask on [Zulip] or in the issue/PR.
|
don't hesitate to ask on [Zulip] or in the issue/PR.
|
||||||
|
|
||||||
[utils]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/mod.rs
|
[utils]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_utils/src/lib.rs
|
||||||
[if_chain]: https://docs.rs/if_chain/*/if_chain/
|
[if_chain]: https://docs.rs/if_chain/*/if_chain/
|
||||||
[from_expansion]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
|
[from_expansion]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
|
||||||
[in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html
|
[in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html
|
||||||
|
|
|
@ -78,7 +78,7 @@ impl LateLintPass<'_> for MyStructLint {
|
||||||
There are two ways to do this, depending if the target trait is part of lang items.
|
There are two ways to do this, depending if the target trait is part of lang items.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use crate::utils::{implements_trait, match_trait_method, paths};
|
use clippy_utils::{implements_trait, match_trait_method, paths};
|
||||||
|
|
||||||
impl LateLintPass<'_> for MyStructLint {
|
impl LateLintPass<'_> for MyStructLint {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
|
@ -112,7 +112,7 @@ We access lang items through the type context `tcx`. `tcx` is of type [`TyCtxt`]
|
||||||
To check if our type defines a method called `some_method`:
|
To check if our type defines a method called `some_method`:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use crate::utils::{is_type_diagnostic_item, return_ty};
|
use clippy_utils::{is_type_diagnostic_item, return_ty};
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
|
impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
|
||||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
|
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
|
||||||
|
@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
|
||||||
|
|
||||||
# Dealing with macros
|
# Dealing with macros
|
||||||
|
|
||||||
There are several helpers in Clippy's utils to deal with macros:
|
There are several helpers in [`clippy_utils`][utils] to deal with macros:
|
||||||
|
|
||||||
- `in_macro()`: detect if the given span is expanded by a macro
|
- `in_macro()`: detect if the given span is expanded by a macro
|
||||||
|
|
||||||
|
@ -199,4 +199,5 @@ assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true);
|
||||||
[LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html
|
[LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html
|
||||||
[TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html
|
[TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html
|
||||||
[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty
|
[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty
|
||||||
[paths]: ../clippy_lints/src/utils/paths.rs
|
[paths]: ../clippy_utils/src/paths.rs
|
||||||
|
[utils]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_utils/src/lib.rs
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
clippy 0.1.51 (7f5bb7fd0 2021-02-06)
|
clippy 0.1.52 (697f3b6d4 2021-02-22)
|
||||||
|
|
||||||
cargo-0.49.0//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/macros/mod.rs:409:34 clippy::match_same_arms "this `match` has identical arm bodies"
|
|
||||||
cargo-0.49.0/build.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.categories` metadata"
|
cargo-0.49.0/build.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.categories` metadata"
|
||||||
cargo-0.49.0/build.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.keywords` metadata"
|
cargo-0.49.0/build.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.keywords` metadata"
|
||||||
cargo-0.49.0/src/bin/cargo/cli.rs:104:34 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
cargo-0.49.0/src/bin/cargo/cli.rs:104:34 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
||||||
|
@ -22,6 +21,7 @@ cargo-0.49.0/src/bin/cargo/commands/check.rs:1:5 clippy::wildcard_imports "usage
|
||||||
cargo-0.49.0/src/bin/cargo/commands/clean.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
|
cargo-0.49.0/src/bin/cargo/commands/clean.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
|
||||||
cargo-0.49.0/src/bin/cargo/commands/doc.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
|
cargo-0.49.0/src/bin/cargo/commands/doc.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
|
||||||
cargo-0.49.0/src/bin/cargo/commands/fetch.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
|
cargo-0.49.0/src/bin/cargo/commands/fetch.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
|
||||||
|
cargo-0.49.0/src/bin/cargo/commands/fetch.rs:22:5 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
cargo-0.49.0/src/bin/cargo/commands/fix.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
|
cargo-0.49.0/src/bin/cargo/commands/fix.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
|
||||||
cargo-0.49.0/src/bin/cargo/commands/generate_lockfile.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
|
cargo-0.49.0/src/bin/cargo/commands/generate_lockfile.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
|
||||||
cargo-0.49.0/src/bin/cargo/commands/git_checkout.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
|
cargo-0.49.0/src/bin/cargo/commands/git_checkout.rs:1:5 clippy::wildcard_imports "usage of wildcard import"
|
||||||
|
@ -99,10 +99,10 @@ cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:411:9 clippy::
|
||||||
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:420:69 clippy::doc_markdown "you should put `mode/target_kind` between ticks in the documentation"
|
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:420:69 clippy::doc_markdown "you should put `mode/target_kind` between ticks in the documentation"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:423:19 clippy::doc_markdown "you should put `CrateTypes` between ticks in the documentation"
|
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:423:19 clippy::doc_markdown "you should put `CrateTypes` between ticks in the documentation"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:424:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:424:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:424:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:469:58 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:469:58 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:603:19 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:603:19 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:665:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:665:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
|
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:697:12 clippy::inconsistent_struct_constructor "inconsistent struct constructor"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:82:31 clippy::doc_markdown "you should put `FileType` between ticks in the documentation"
|
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:82:31 clippy::doc_markdown "you should put `FileType` between ticks in the documentation"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:83:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:83:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:84:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:84:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
||||||
|
@ -151,7 +151,6 @@ cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:361:5 clippy::must_use_candi
|
||||||
cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:374:43 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation"
|
cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:374:43 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:378:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:378:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:383:41 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation"
|
cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:383:41 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:384:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:384:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:384:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:391:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:391:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:397:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:397:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
|
@ -173,14 +172,13 @@ cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:481:5 clippy::missing_error
|
||||||
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:481:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:481:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:48:56 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation"
|
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:48:56 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:561:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:561:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:561:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:567:20 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:567:20 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:576:28 clippy::shadow_unrelated "`mut value` is being shadowed"
|
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:576:28 clippy::shadow_unrelated "`mut value` is being shadowed"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:606:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:606:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:688:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:688:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:756:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:756:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:762:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:762:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:762:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
|
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:762:5 clippy::unnecessary_wraps "this function's return value is unnecessary"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:823:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:823:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1021:51 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1021:51 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1656:16 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
cargo-0.49.0/src/cargo/core/compiler/fingerprint.rs:1656:16 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
||||||
|
@ -236,7 +234,7 @@ cargo-0.49.0/src/cargo/core/compiler/job_queue.rs:93:24 clippy::doc_markdown "yo
|
||||||
cargo-0.49.0/src/cargo/core/compiler/links.rs:8:1 clippy::module_name_repetitions "item name ends with its containing module's name"
|
cargo-0.49.0/src/cargo/core/compiler/links.rs:8:1 clippy::module_name_repetitions "item name ends with its containing module's name"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:1016:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:1016:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:1094:19 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:1094:19 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:1131:1 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:1131:1 clippy::unnecessary_wraps "this function's return value is unnecessary"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:1268:34 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:1268:34 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:1277:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:1277:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:179:1 clippy::too_many_lines "this function has too many lines (162/100)"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:179:1 clippy::too_many_lines "this function has too many lines (162/100)"
|
||||||
|
@ -245,13 +243,13 @@ cargo-0.49.0/src/cargo/core/compiler/mod.rs:201:25 clippy::single_match_else "yo
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:267:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:267:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:324:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:324:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:364:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:364:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:364:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:364:5 clippy::unnecessary_wraps "this function's return value is unnecessary"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:392:45 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:392:45 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:415:23 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:415:23 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:464:18 clippy::ptr_arg "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do."
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:464:18 clippy::ptr_arg "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do."
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:488:61 clippy::ptr_arg "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do."
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:488:61 clippy::ptr_arg "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do."
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:667:15 clippy::similar_names "binding's name is too similar to existing binding"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:667:15 clippy::similar_names "binding's name is too similar to existing binding"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:693:1 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:693:1 clippy::unnecessary_wraps "this function's return value is unnecessary"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:725:42 clippy::match_same_arms "this `match` has identical arm bodies"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:725:42 clippy::match_same_arms "this `match` has identical arm bodies"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:736:1 clippy::too_many_lines "this function has too many lines (141/100)"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:736:1 clippy::too_many_lines "this function has too many lines (141/100)"
|
||||||
cargo-0.49.0/src/cargo/core/compiler/mod.rs:73:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/compiler/mod.rs:73:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
|
@ -290,7 +288,6 @@ cargo-0.49.0/src/cargo/core/compiler/unit_graph.rs:65:1 clippy::missing_errors_d
|
||||||
cargo-0.49.0/src/cargo/core/compiler/unit_graph.rs:65:1 clippy::module_name_repetitions "item name ends with its containing module's name"
|
cargo-0.49.0/src/cargo/core/compiler/unit_graph.rs:65:1 clippy::module_name_repetitions "item name ends with its containing module's name"
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:157:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/dependency.rs:157:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:182:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/dependency.rs:182:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:203:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:203:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/dependency.rs:203:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:224:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/dependency.rs:224:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:23:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
|
cargo-0.49.0/src/cargo/core/dependency.rs:23:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
|
||||||
|
@ -300,13 +297,10 @@ cargo-0.49.0/src/cargo/core/dependency.rs:274:5 clippy::must_use_candidate "this
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:278:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/dependency.rs:278:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:287:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/dependency.rs:287:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:291:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/dependency.rs:291:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:296:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:305:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/dependency.rs:305:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:311:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/dependency.rs:311:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:319:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/dependency.rs:319:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:323:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:337:75 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/core/dependency.rs:337:75 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:379:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:397:56 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/core/dependency.rs:397:56 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:403:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/dependency.rs:403:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/dependency.rs:408:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/dependency.rs:408:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
|
@ -452,12 +446,10 @@ cargo-0.49.0/src/cargo/core/package.rs:287:1 clippy::module_name_repetitions "it
|
||||||
cargo-0.49.0/src/cargo/core/package.rs:385:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/package.rs:385:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/package.rs:421:5 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)"
|
cargo-0.49.0/src/cargo/core/package.rs:421:5 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)"
|
||||||
cargo-0.49.0/src/cargo/core/package.rs:425:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/package.rs:425:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/package.rs:425:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/package.rs:452:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/package.rs:452:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/package.rs:453:60 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/core/package.rs:453:60 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/core/package.rs:459:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/package.rs:459:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/package.rs:473:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/package.rs:473:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/package.rs:552:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/package.rs:587:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/package.rs:587:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/package.rs:588:9 clippy::needless_question_mark "Question mark operator is useless here"
|
cargo-0.49.0/src/cargo/core/package.rs:588:9 clippy::needless_question_mark "Question mark operator is useless here"
|
||||||
cargo-0.49.0/src/cargo/core/package.rs:682:46 clippy::cast_possible_truncation "casting `f64` to `u64` may truncate the value"
|
cargo-0.49.0/src/cargo/core/package.rs:682:46 clippy::cast_possible_truncation "casting `f64` to `u64` may truncate the value"
|
||||||
|
@ -490,13 +482,12 @@ cargo-0.49.0/src/cargo/core/package_id_spec.rs:51:5 clippy::missing_errors_doc "
|
||||||
cargo-0.49.0/src/cargo/core/package_id_spec.rs:51:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
cargo-0.49.0/src/cargo/core/package_id_spec.rs:51:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
||||||
cargo-0.49.0/src/cargo/core/package_id_spec.rs:77:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/package_id_spec.rs:77:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/package_id_spec.rs:88:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/package_id_spec.rs:88:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/profiles.rs:1004:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/profiles.rs:1004:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/profiles.rs:1004:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/profiles.rs:1014:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/profiles.rs:1014:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/profiles.rs:1018:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/profiles.rs:1018:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/profiles.rs:1028:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/profiles.rs:1028:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/profiles.rs:106:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
cargo-0.49.0/src/cargo/core/profiles.rs:106:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
cargo-0.49.0/src/cargo/core/profiles.rs:143:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
|
cargo-0.49.0/src/cargo/core/profiles.rs:143:5 clippy::unnecessary_wraps "this function's return value is unnecessary"
|
||||||
cargo-0.49.0/src/cargo/core/profiles.rs:286:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
cargo-0.49.0/src/cargo/core/profiles.rs:286:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
||||||
cargo-0.49.0/src/cargo/core/profiles.rs:286:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/profiles.rs:286:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/profiles.rs:294:40 clippy::if_not_else "unnecessary boolean `not` operation"
|
cargo-0.49.0/src/cargo/core/profiles.rs:294:40 clippy::if_not_else "unnecessary boolean `not` operation"
|
||||||
|
@ -522,9 +513,7 @@ cargo-0.49.0/src/cargo/core/registry.rs:19:5 clippy::missing_errors_doc "docs fo
|
||||||
cargo-0.49.0/src/cargo/core/registry.rs:240:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/registry.rs:240:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/registry.rs:26:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/registry.rs:26:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/registry.rs:344:49 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/core/registry.rs:344:49 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/core/registry.rs:358:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/registry.rs:369:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/registry.rs:369:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/registry.rs:424:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/registry.rs:424:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/registry.rs:424:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/registry.rs:49:1 clippy::module_name_repetitions "item name ends with its containing module's name"
|
cargo-0.49.0/src/cargo/core/registry.rs:49:1 clippy::module_name_repetitions "item name ends with its containing module's name"
|
||||||
cargo-0.49.0/src/cargo/core/registry.rs:520:17 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
cargo-0.49.0/src/cargo/core/registry.rs:520:17 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
||||||
|
@ -538,7 +527,6 @@ cargo-0.49.0/src/cargo/core/resolver/context.rs:274:53 clippy::redundant_closure
|
||||||
cargo-0.49.0/src/cargo/core/resolver/context.rs:42:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
cargo-0.49.0/src/cargo/core/resolver/context.rs:42:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
||||||
cargo-0.49.0/src/cargo/core/resolver/context.rs:74:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/resolver/context.rs:74:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::too_many_lines "this function has too many lines (164/100)"
|
cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::too_many_lines "this function has too many lines (164/100)"
|
||||||
cargo-0.49.0/src/cargo/core/resolver/encode.rs:339:17 clippy::match_wildcard_for_single_variants "wildcard match will miss any future added variants"
|
cargo-0.49.0/src/cargo/core/resolver/encode.rs:339:17 clippy::match_wildcard_for_single_variants "wildcard match will miss any future added variants"
|
||||||
cargo-0.49.0/src/cargo/core/resolver/encode.rs:438:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
cargo-0.49.0/src/cargo/core/resolver/encode.rs:438:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
|
@ -596,7 +584,6 @@ cargo-0.49.0/src/cargo/core/resolver/resolve.rs:255:5 clippy::must_use_candidate
|
||||||
cargo-0.49.0/src/cargo/core/resolver/resolve.rs:259:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/resolver/resolve.rs:259:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/resolver/resolve.rs:263:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/resolver/resolve.rs:263:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/resolver/resolve.rs:269:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/resolver/resolve.rs:269:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/resolver/resolve.rs:273:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/resolver/resolve.rs:273:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/resolver/resolve.rs:273:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/resolver/resolve.rs:274:9 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
|
cargo-0.49.0/src/cargo/core/resolver/resolve.rs:274:9 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
|
||||||
cargo-0.49.0/src/cargo/core/resolver/resolve.rs:280:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/resolver/resolve.rs:280:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
|
@ -639,6 +626,7 @@ cargo-0.49.0/src/cargo/core/shell.rs:314:5 clippy::must_use_candidate "this meth
|
||||||
cargo-0.49.0/src/cargo/core/shell.rs:322:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/shell.rs:322:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/shell.rs:330:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/shell.rs:330:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/shell.rs:345:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
cargo-0.49.0/src/cargo/core/shell.rs:345:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
||||||
|
cargo-0.49.0/src/cargo/core/shell.rs:459:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
cargo-0.49.0/src/cargo/core/shell.rs:98:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/shell.rs:98:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/source/mod.rs:103:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/source/mod.rs:103:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/source/mod.rs:247:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
cargo-0.49.0/src/cargo/core/source/mod.rs:247:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
||||||
|
@ -682,7 +670,6 @@ cargo-0.49.0/src/cargo/core/source/source_id.rs:241:5 clippy::must_use_candidate
|
||||||
cargo-0.49.0/src/cargo/core/source/source_id.rs:252:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/source/source_id.rs:252:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/source/source_id.rs:257:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/source/source_id.rs:257:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/source/source_id.rs:262:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/source/source_id.rs:262:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/source/source_id.rs:262:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/core/source/source_id.rs:305:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/source/source_id.rs:305:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/source/source_id.rs:310:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/source/source_id.rs:310:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/core/source/source_id.rs:318:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/core/source/source_id.rs:318:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
|
@ -780,7 +767,6 @@ cargo-0.49.0/src/cargo/core/workspace.rs:849:5 clippy::missing_panics_doc "docs
|
||||||
cargo-0.49.0/src/cargo/core/workspace.rs:893:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/workspace.rs:893:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/workspace.rs:906:24 clippy::redundant_else "redundant else block"
|
cargo-0.49.0/src/cargo/core/workspace.rs:906:24 clippy::redundant_else "redundant else block"
|
||||||
cargo-0.49.0/src/cargo/core/workspace.rs:932:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/core/workspace.rs:932:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/core/workspace.rs:932:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/lib.rs:177:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
cargo-0.49.0/src/cargo/lib.rs:177:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
||||||
cargo-0.49.0/src/cargo/lib.rs:177:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/lib.rs:177:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/lib.rs:180:36 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/lib.rs:180:36 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
|
@ -808,7 +794,6 @@ cargo-0.49.0/src/cargo/ops/cargo_compile.rs:249:1 clippy::missing_errors_doc "do
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:258:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:258:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:267:16 clippy::needless_question_mark "Question mark operator is useless here"
|
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:267:16 clippy::needless_question_mark "Question mark operator is useless here"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:275:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:275:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:275:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:275:1 clippy::too_many_lines "this function has too many lines (219/100)"
|
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:275:1 clippy::too_many_lines "this function has too many lines (219/100)"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:468:9 clippy::default_trait_access "calling `std::collections::HashMap::default()` is more clear than this expression"
|
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:468:9 clippy::default_trait_access "calling `std::collections::HashMap::default()` is more clear than this expression"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:548:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:548:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
|
@ -824,7 +809,6 @@ cargo-0.49.0/src/cargo/ops/cargo_compile.rs:612:21 clippy::doc_markdown "you sho
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:613:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:613:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:618:9 clippy::similar_names "binding's name is too similar to existing binding"
|
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:618:9 clippy::similar_names "binding's name is too similar to existing binding"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:641:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:641:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:652:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:652:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:652:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:655:50 clippy::match_same_arms "this `match` has identical arm bodies"
|
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:655:50 clippy::match_same_arms "this `match` has identical arm bodies"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:673:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/ops/cargo_compile.rs:673:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
|
@ -879,6 +863,7 @@ cargo-0.49.0/src/cargo/ops/cargo_package.rs:394:5 clippy::items_after_statements
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_package.rs:425:61 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/ops/cargo_package.rs:425:61 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_package.rs:459:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
cargo-0.49.0/src/cargo/ops/cargo_package.rs:459:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_package.rs:66:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/ops/cargo_package.rs:66:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
|
cargo-0.49.0/src/cargo/ops/cargo_package.rs:69:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_package.rs:93:20 clippy::if_not_else "unnecessary boolean `not` operation"
|
cargo-0.49.0/src/cargo/ops/cargo_package.rs:93:20 clippy::if_not_else "unnecessary boolean `not` operation"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_pkgid.rs:5:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/ops/cargo_pkgid.rs:5:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:14:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:14:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
|
@ -893,7 +878,6 @@ cargo-0.49.0/src/cargo/ops/cargo_run.rs:37:16 clippy::redundant_else "redundant
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_run.rs:53:9 clippy::if_not_else "unnecessary boolean `not` operation"
|
cargo-0.49.0/src/cargo/ops/cargo_run.rs:53:9 clippy::if_not_else "unnecessary boolean `not` operation"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_run.rs:65:16 clippy::redundant_else "redundant else block"
|
cargo-0.49.0/src/cargo/ops/cargo_run.rs:65:16 clippy::redundant_else "redundant else block"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_run.rs:9:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/ops/cargo_run.rs:9:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_run.rs:9:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_test.rs:16:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/ops/cargo_test.rs:16:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_test.rs:43:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/ops/cargo_test.rs:43:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/ops/cargo_test.rs:84:17 clippy::similar_names "binding's name is too similar to existing binding"
|
cargo-0.49.0/src/cargo/ops/cargo_test.rs:84:17 clippy::similar_names "binding's name is too similar to existing binding"
|
||||||
|
@ -904,7 +888,7 @@ cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:233:21 clippy::si
|
||||||
cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:244:22 clippy::doc_markdown "you should put `PackageId` between ticks in the documentation"
|
cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:244:22 clippy::doc_markdown "you should put `PackageId` between ticks in the documentation"
|
||||||
cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:244:63 clippy::doc_markdown "you should put `PackageId` between ticks in the documentation"
|
cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:244:63 clippy::doc_markdown "you should put `PackageId` between ticks in the documentation"
|
||||||
cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:253:17 clippy::if_not_else "unnecessary boolean `not` operation"
|
cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:253:17 clippy::if_not_else "unnecessary boolean `not` operation"
|
||||||
cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:370:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
|
cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:370:5 clippy::unnecessary_wraps "this function's return value is unnecessary"
|
||||||
cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:505:8 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
|
cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:505:8 clippy::map_unwrap_or "called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead"
|
||||||
cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:525:10 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
|
cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:525:10 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
|
||||||
cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:542:27 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/ops/common_for_install_and_uninstall.rs:542:27 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
|
@ -967,7 +951,6 @@ cargo-0.49.0/src/cargo/ops/registry.rs:794:16 clippy::single_match_else "you see
|
||||||
cargo-0.49.0/src/cargo/ops/registry.rs:828:14 clippy::doc_markdown "you should put `SourceId` between ticks in the documentation"
|
cargo-0.49.0/src/cargo/ops/registry.rs:828:14 clippy::doc_markdown "you should put `SourceId` between ticks in the documentation"
|
||||||
cargo-0.49.0/src/cargo/ops/registry.rs:848:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/ops/registry.rs:848:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
||||||
cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::too_many_lines "this function has too many lines (137/100)"
|
cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::too_many_lines "this function has too many lines (137/100)"
|
||||||
cargo-0.49.0/src/cargo/ops/resolve.rs:241:28 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
cargo-0.49.0/src/cargo/ops/resolve.rs:241:28 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
||||||
|
@ -997,6 +980,7 @@ cargo-0.49.0/src/cargo/ops/tree/mod.rs:21:1 clippy::struct_excessive_bools "more
|
||||||
cargo-0.49.0/src/cargo/ops/tree/mod.rs:360:30 clippy::match_same_arms "this `match` has identical arm bodies"
|
cargo-0.49.0/src/cargo/ops/tree/mod.rs:360:30 clippy::match_same_arms "this `match` has identical arm bodies"
|
||||||
cargo-0.49.0/src/cargo/ops/tree/mod.rs:58:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/ops/tree/mod.rs:58:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/ops/vendor.rs:14:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
cargo-0.49.0/src/cargo/ops/vendor.rs:14:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
||||||
|
cargo-0.49.0/src/cargo/ops/vendor.rs:215:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
cargo-0.49.0/src/cargo/ops/vendor.rs:21:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/ops/vendor.rs:21:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/ops/vendor.rs:21:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
cargo-0.49.0/src/cargo/ops/vendor.rs:21:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
||||||
cargo-0.49.0/src/cargo/ops/vendor.rs:314:34 clippy::match_same_arms "this `match` has identical arm bodies"
|
cargo-0.49.0/src/cargo/ops/vendor.rs:314:34 clippy::match_same_arms "this `match` has identical arm bodies"
|
||||||
|
@ -1017,7 +1001,6 @@ cargo-0.49.0/src/cargo/sources/directory.rs:14:1 clippy::module_name_repetitions
|
||||||
cargo-0.49.0/src/cargo/sources/directory.rs:90:56 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/sources/directory.rs:90:56 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/sources/git/source.rs:14:1 clippy::module_name_repetitions "item name ends with its containing module's name"
|
cargo-0.49.0/src/cargo/sources/git/source.rs:14:1 clippy::module_name_repetitions "item name ends with its containing module's name"
|
||||||
cargo-0.49.0/src/cargo/sources/git/source.rs:25:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/sources/git/source.rs:25:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/sources/git/source.rs:25:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/sources/git/source.rs:49:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/sources/git/source.rs:49:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/sources/git/source.rs:53:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/sources/git/source.rs:53:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/sources/git/source.rs:53:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
cargo-0.49.0/src/cargo/sources/git/source.rs:53:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
||||||
|
@ -1032,7 +1015,6 @@ cargo-0.49.0/src/cargo/sources/git/utils.rs:184:5 clippy::missing_errors_doc "do
|
||||||
cargo-0.49.0/src/cargo/sources/git/utils.rs:188:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/sources/git/utils.rs:188:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/sources/git/utils.rs:242:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/sources/git/utils.rs:242:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/sources/git/utils.rs:253:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/sources/git/utils.rs:253:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/sources/git/utils.rs:253:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/sources/git/utils.rs:262:13 clippy::if_not_else "unnecessary boolean `not` operation"
|
cargo-0.49.0/src/cargo/sources/git/utils.rs:262:13 clippy::if_not_else "unnecessary boolean `not` operation"
|
||||||
cargo-0.49.0/src/cargo/sources/git/utils.rs:289:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/sources/git/utils.rs:289:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/sources/git/utils.rs:294:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/sources/git/utils.rs:294:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
|
@ -1062,7 +1044,6 @@ cargo-0.49.0/src/cargo/sources/path.rs:429:5 clippy::missing_errors_doc "docs fo
|
||||||
cargo-0.49.0/src/cargo/sources/path.rs:460:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/sources/path.rs:460:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/sources/path.rs:473:43 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/sources/path.rs:473:43 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/sources/path.rs:482:43 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/sources/path.rs:482:43 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/sources/path.rs:55:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/sources/path.rs:63:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/sources/path.rs:63:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/sources/path.rs:77:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/sources/path.rs:77:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/sources/path.rs:98:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/sources/path.rs:98:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
|
@ -1142,7 +1123,6 @@ cargo-0.49.0/src/cargo/util/config/mod.rs:100:71 clippy::doc_markdown "you shoul
|
||||||
cargo-0.49.0/src/cargo/util/config/mod.rs:1049:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/config/mod.rs:1049:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/config/mod.rs:1064:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/config/mod.rs:1064:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/config/mod.rs:1090:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/config/mod.rs:1090:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/config/mod.rs:1090:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/util/config/mod.rs:1166:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/config/mod.rs:1166:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/config/mod.rs:1179:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/config/mod.rs:1179:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/config/mod.rs:1181:33 clippy::needless_question_mark "Question mark operator is useless here"
|
cargo-0.49.0/src/cargo/util/config/mod.rs:1181:33 clippy::needless_question_mark "Question mark operator is useless here"
|
||||||
|
@ -1157,7 +1137,6 @@ cargo-0.49.0/src/cargo/util/config/mod.rs:1225:5 clippy::missing_errors_doc "doc
|
||||||
cargo-0.49.0/src/cargo/util/config/mod.rs:1229:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/config/mod.rs:1229:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/config/mod.rs:124:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
|
cargo-0.49.0/src/cargo/util/config/mod.rs:124:1 clippy::struct_excessive_bools "more than 3 bools in a struct"
|
||||||
cargo-0.49.0/src/cargo/util/config/mod.rs:1254:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/config/mod.rs:1254:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/config/mod.rs:1263:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/util/config/mod.rs:1279:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/config/mod.rs:1279:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/config/mod.rs:1281:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
cargo-0.49.0/src/cargo/util/config/mod.rs:1281:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
||||||
cargo-0.49.0/src/cargo/util/config/mod.rs:1323:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
cargo-0.49.0/src/cargo/util/config/mod.rs:1323:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
|
@ -1224,7 +1203,6 @@ cargo-0.49.0/src/cargo/util/dependency_queue.rs:151:5 clippy::must_use_candidate
|
||||||
cargo-0.49.0/src/cargo/util/dependency_queue.rs:156:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/util/dependency_queue.rs:156:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/util/dependency_queue.rs:168:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
cargo-0.49.0/src/cargo/util/dependency_queue.rs:168:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
||||||
cargo-0.49.0/src/cargo/util/dependency_queue.rs:46:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/util/dependency_queue.rs:46:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/util/dependency_queue.rs:66:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/util/dependency_queue.rs:91:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
cargo-0.49.0/src/cargo/util/dependency_queue.rs:91:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
cargo-0.49.0/src/cargo/util/diagnostic_server.rs:218:1 clippy::module_name_repetitions "item name ends with its containing module's name"
|
cargo-0.49.0/src/cargo/util/diagnostic_server.rs:218:1 clippy::module_name_repetitions "item name ends with its containing module's name"
|
||||||
cargo-0.49.0/src/cargo/util/diagnostic_server.rs:230:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/diagnostic_server.rs:230:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
|
@ -1238,7 +1216,6 @@ cargo-0.49.0/src/cargo/util/errors.rs:143:5 clippy::must_use_candidate "this met
|
||||||
cargo-0.49.0/src/cargo/util/errors.rs:150:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/util/errors.rs:150:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/util/errors.rs:15:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/errors.rs:15:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/errors.rs:237:5 clippy::pub_enum_variant_names "variant name ends with the enum's name"
|
cargo-0.49.0/src/cargo/util/errors.rs:237:5 clippy::pub_enum_variant_names "variant name ends with the enum's name"
|
||||||
cargo-0.49.0/src/cargo/util/errors.rs:245:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/util/errors.rs:245:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/util/errors.rs:245:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/util/errors.rs:321:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/util/errors.rs:321:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/util/errors.rs:328:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/util/errors.rs:328:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
|
@ -1263,12 +1240,11 @@ cargo-0.49.0/src/cargo/util/flock.rs:335:23 clippy::cast_possible_truncation "ca
|
||||||
cargo-0.49.0/src/cargo/util/flock.rs:335:23 clippy::cast_sign_loss "casting `i64` to `u32` may lose the sign of the value"
|
cargo-0.49.0/src/cargo/util/flock.rs:335:23 clippy::cast_sign_loss "casting `i64` to `u32` may lose the sign of the value"
|
||||||
cargo-0.49.0/src/cargo/util/flock.rs:335:44 clippy::cast_possible_truncation "casting `i64` to `u32` may truncate the value"
|
cargo-0.49.0/src/cargo/util/flock.rs:335:44 clippy::cast_possible_truncation "casting `i64` to `u32` may truncate the value"
|
||||||
cargo-0.49.0/src/cargo/util/flock.rs:379:35 clippy::match_same_arms "this `match` has identical arm bodies"
|
cargo-0.49.0/src/cargo/util/flock.rs:379:35 clippy::match_same_arms "this `match` has identical arm bodies"
|
||||||
cargo-0.49.0/src/cargo/util/flock.rs:37:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/util/flock.rs:37:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/util/flock.rs:37:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/util/flock.rs:43:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/util/flock.rs:43:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/util/flock.rs:43:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/util/flock.rs:52:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/flock.rs:52:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/flock.rs:52:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
cargo-0.49.0/src/cargo/util/flock.rs:52:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
||||||
|
cargo-0.49.0/src/cargo/util/flock.rs:96:17 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
cargo-0.49.0/src/cargo/util/graph.rs:10:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/util/graph.rs:10:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/util/graph.rs:41:51 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/util/graph.rs:41:51 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/util/graph.rs:45:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/util/graph.rs:45:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
|
@ -1331,8 +1307,8 @@ cargo-0.49.0/src/cargo/util/paths.rs:445:1 clippy::missing_errors_doc "docs for
|
||||||
cargo-0.49.0/src/cargo/util/paths.rs:459:45 clippy::redundant_closure_for_method_calls "redundant closure found"
|
cargo-0.49.0/src/cargo/util/paths.rs:459:45 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
cargo-0.49.0/src/cargo/util/paths.rs:469:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/paths.rs:469:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/paths.rs:469:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
cargo-0.49.0/src/cargo/util/paths.rs:469:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
||||||
|
cargo-0.49.0/src/cargo/util/paths.rs:514:5 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
cargo-0.49.0/src/cargo/util/paths.rs:54:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/util/paths.rs:54:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/util/paths.rs:61:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
cargo-0.49.0/src/cargo/util/paths.rs:61:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/util/paths.rs:61:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/util/paths.rs:63:19 clippy::option_if_let_else "use Option::map_or_else instead of an if let/else"
|
cargo-0.49.0/src/cargo/util/paths.rs:63:19 clippy::option_if_let_else "use Option::map_or_else instead of an if let/else"
|
||||||
cargo-0.49.0/src/cargo/util/paths.rs:88:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/paths.rs:88:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
|
@ -1346,6 +1322,7 @@ cargo-0.49.0/src/cargo/util/process_builder.rs:185:5 clippy::missing_errors_doc
|
||||||
cargo-0.49.0/src/cargo/util/process_builder.rs:190:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/process_builder.rs:190:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/process_builder.rs:218:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/process_builder.rs:218:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/process_builder.rs:218:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
cargo-0.49.0/src/cargo/util/process_builder.rs:218:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
||||||
|
cargo-0.49.0/src/cargo/util/process_builder.rs:278:22 clippy::inconsistent_struct_constructor "inconsistent struct constructor"
|
||||||
cargo-0.49.0/src/cargo/util/process_builder.rs:307:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/util/process_builder.rs:307:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
cargo-0.49.0/src/cargo/util/process_builder.rs:343:39 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
|
cargo-0.49.0/src/cargo/util/process_builder.rs:343:39 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
|
||||||
cargo-0.49.0/src/cargo/util/progress.rs:122:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/progress.rs:122:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
|
@ -1386,6 +1363,7 @@ cargo-0.49.0/src/cargo/util/rustc.rs:115:5 clippy::doc_markdown "you should put
|
||||||
cargo-0.49.0/src/cargo/util/rustc.rs:162:17 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
cargo-0.49.0/src/cargo/util/rustc.rs:162:17 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
cargo-0.49.0/src/cargo/util/rustc.rs:39:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/rustc.rs:39:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/sha256.rs:10:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
cargo-0.49.0/src/cargo/util/sha256.rs:10:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
|
cargo-0.49.0/src/cargo/util/sha256.rs:16:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
cargo-0.49.0/src/cargo/util/sha256.rs:20:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/sha256.rs:20:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/sha256.rs:31:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
cargo-0.49.0/src/cargo/util/sha256.rs:31:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
cargo-0.49.0/src/cargo/util/sha256.rs:40:24 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
|
cargo-0.49.0/src/cargo/util/sha256.rs:40:24 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
|
||||||
|
@ -1451,6 +1429,7 @@ iron-0.6.1/src/iron.rs:133:5 clippy::missing_errors_doc "docs for function retur
|
||||||
iron-0.6.1/src/iron.rs:143:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
iron-0.6.1/src/iron.rs:143:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
iron-0.6.1/src/iron.rs:149:13 clippy::redundant_field_names "redundant field names in struct initialization"
|
iron-0.6.1/src/iron.rs:149:13 clippy::redundant_field_names "redundant field names in struct initialization"
|
||||||
iron-0.6.1/src/iron.rs:167:49 clippy::similar_names "binding's name is too similar to existing binding"
|
iron-0.6.1/src/iron.rs:167:49 clippy::similar_names "binding's name is too similar to existing binding"
|
||||||
|
iron-0.6.1/src/iron.rs:196:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
iron-0.6.1/src/iron.rs:80:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
iron-0.6.1/src/iron.rs:80:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
iron-0.6.1/src/iron.rs:85:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
iron-0.6.1/src/iron.rs:85:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
iron-0.6.1/src/iron.rs:90:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
iron-0.6.1/src/iron.rs:90:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
|
@ -1991,18 +1970,15 @@ log-0.4.11/src/lib.rs:1118:5 clippy::must_use_candidate "this method could have
|
||||||
log-0.4.11/src/lib.rs:1177:1 clippy::inline_always "you have declared `#[inline(always)]` on `max_level`. This is usually a bad idea"
|
log-0.4.11/src/lib.rs:1177:1 clippy::inline_always "you have declared `#[inline(always)]` on `max_level`. This is usually a bad idea"
|
||||||
log-0.4.11/src/lib.rs:1178:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
|
log-0.4.11/src/lib.rs:1178:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
|
||||||
log-0.4.11/src/lib.rs:1306:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
log-0.4.11/src/lib.rs:1306:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
log-0.4.11/src/lib.rs:1306:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
log-0.4.11/src/lib.rs:1358:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
|
log-0.4.11/src/lib.rs:1358:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
|
||||||
log-0.4.11/src/lib.rs:1359:5 clippy::if_not_else "unnecessary `!=` operation"
|
log-0.4.11/src/lib.rs:1359:5 clippy::if_not_else "unnecessary `!=` operation"
|
||||||
log-0.4.11/src/lib.rs:1407:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
|
log-0.4.11/src/lib.rs:1407:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute"
|
||||||
log-0.4.11/src/lib.rs:329:27 clippy::derive_hash_xor_eq "you are deriving `Hash` but have implemented `PartialEq` explicitly"
|
|
||||||
log-0.4.11/src/lib.rs:356:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
|
log-0.4.11/src/lib.rs:356:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
|
||||||
log-0.4.11/src/lib.rs:448:12 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
|
log-0.4.11/src/lib.rs:448:12 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation"
|
||||||
log-0.4.11/src/lib.rs:500:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
log-0.4.11/src/lib.rs:500:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
log-0.4.11/src/lib.rs:506:28 clippy::trivially_copy_pass_by_ref "this argument (8 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
|
log-0.4.11/src/lib.rs:506:28 clippy::trivially_copy_pass_by_ref "this argument (8 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
|
||||||
log-0.4.11/src/lib.rs:506:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
log-0.4.11/src/lib.rs:506:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
||||||
log-0.4.11/src/lib.rs:506:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
log-0.4.11/src/lib.rs:506:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
log-0.4.11/src/lib.rs:520:27 clippy::derive_hash_xor_eq "you are deriving `Hash` but have implemented `PartialEq` explicitly"
|
|
||||||
log-0.4.11/src/lib.rs:538:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
|
log-0.4.11/src/lib.rs:538:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type"
|
||||||
log-0.4.11/src/lib.rs:653:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
log-0.4.11/src/lib.rs:653:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
log-0.4.11/src/lib.rs:661:21 clippy::trivially_copy_pass_by_ref "this argument (8 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
|
log-0.4.11/src/lib.rs:661:21 clippy::trivially_copy_pass_by_ref "this argument (8 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)"
|
||||||
|
@ -2112,7 +2088,6 @@ puffin-02dd4a3/puffin/src/data.rs:137:24 clippy::match_same_arms "this `match` h
|
||||||
puffin-02dd4a3/puffin/src/data.rs:177:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
puffin-02dd4a3/puffin/src/data.rs:177:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
puffin-02dd4a3/puffin/src/data.rs:211:21 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
|
puffin-02dd4a3/puffin/src/data.rs:211:21 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
|
||||||
puffin-02dd4a3/puffin/src/data.rs:24:5 clippy::wildcard_imports "usage of wildcard import"
|
puffin-02dd4a3/puffin/src/data.rs:24:5 clippy::wildcard_imports "usage of wildcard import"
|
||||||
puffin-02dd4a3/puffin/src/data.rs:75:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
puffin-02dd4a3/puffin/src/lib.rs:113:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
puffin-02dd4a3/puffin/src/lib.rs:113:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
puffin-02dd4a3/puffin/src/lib.rs:147:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
puffin-02dd4a3/puffin/src/lib.rs:147:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
puffin-02dd4a3/puffin/src/lib.rs:147:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
puffin-02dd4a3/puffin/src/lib.rs:147:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
||||||
|
@ -2146,7 +2121,6 @@ quote-1.0.7/src/ext.rs:10:1 clippy::module_name_repetitions "item name ends with
|
||||||
quote-1.0.7/src/ext.rs:7:5 clippy::doc_markdown "you should put `TokenStream` between ticks in the documentation"
|
quote-1.0.7/src/ext.rs:7:5 clippy::doc_markdown "you should put `TokenStream` between ticks in the documentation"
|
||||||
quote-1.0.7/src/ident_fragment.rs:13:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
quote-1.0.7/src/ident_fragment.rs:13:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
quote-1.0.7/src/ident_fragment.rs:51:31 clippy::manual_strip "stripping a prefix manually"
|
quote-1.0.7/src/ident_fragment.rs:51:31 clippy::manual_strip "stripping a prefix manually"
|
||||||
quote-1.0.7/src/runtime.rs:332:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
quote-1.0.7/src/runtime.rs:52:5 clippy::module_name_repetitions "item name ends with its containing module's name"
|
quote-1.0.7/src/runtime.rs:52:5 clippy::module_name_repetitions "item name ends with its containing module's name"
|
||||||
quote-1.0.7/src/runtime.rs:63:5 clippy::module_name_repetitions "item name ends with its containing module's name"
|
quote-1.0.7/src/runtime.rs:63:5 clippy::module_name_repetitions "item name ends with its containing module's name"
|
||||||
quote-1.0.7/src/runtime.rs:66:33 clippy::doc_markdown "you should put `DoesNotHaveIter` between ticks in the documentation"
|
quote-1.0.7/src/runtime.rs:66:33 clippy::doc_markdown "you should put `DoesNotHaveIter` between ticks in the documentation"
|
||||||
|
@ -2183,7 +2157,6 @@ rand-0.7.3/src/distributions/binomial.rs:233:32 clippy::cast_precision_loss "cas
|
||||||
rand-0.7.3/src/distributions/binomial.rs:234:27 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
|
rand-0.7.3/src/distributions/binomial.rs:234:27 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
|
||||||
rand-0.7.3/src/distributions/binomial.rs:251:22 clippy::cast_sign_loss "casting `i64` to `u64` may lose the sign of the value"
|
rand-0.7.3/src/distributions/binomial.rs:251:22 clippy::cast_sign_loss "casting `i64` to `u64` may lose the sign of the value"
|
||||||
rand-0.7.3/src/distributions/binomial.rs:255:9 clippy::if_not_else "unnecessary `!=` operation"
|
rand-0.7.3/src/distributions/binomial.rs:255:9 clippy::if_not_else "unnecessary `!=` operation"
|
||||||
rand-0.7.3/src/distributions/binomial.rs:35:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
rand-0.7.3/src/distributions/binomial.rs:35:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
rand-0.7.3/src/distributions/binomial.rs:35:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
rand-0.7.3/src/distributions/binomial.rs:45:17 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
|
rand-0.7.3/src/distributions/binomial.rs:45:17 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
|
||||||
rand-0.7.3/src/distributions/binomial.rs:46:5 clippy::cast_possible_truncation "casting `f64` to `i64` may truncate the value"
|
rand-0.7.3/src/distributions/binomial.rs:46:5 clippy::cast_possible_truncation "casting `f64` to `i64` may truncate the value"
|
||||||
|
@ -2194,25 +2167,18 @@ rand-0.7.3/src/distributions/binomial.rs:81:21 clippy::cast_precision_loss "cast
|
||||||
rand-0.7.3/src/distributions/binomial.rs:82:32 clippy::cast_possible_truncation "casting `u64` to `i32` may truncate the value"
|
rand-0.7.3/src/distributions/binomial.rs:82:32 clippy::cast_possible_truncation "casting `u64` to `i32` may truncate the value"
|
||||||
rand-0.7.3/src/distributions/binomial.rs:88:26 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
|
rand-0.7.3/src/distributions/binomial.rs:88:26 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
|
||||||
rand-0.7.3/src/distributions/binomial.rs:99:21 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
|
rand-0.7.3/src/distributions/binomial.rs:99:21 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
|
||||||
rand-0.7.3/src/distributions/cauchy.rs:33:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
rand-0.7.3/src/distributions/cauchy.rs:33:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
rand-0.7.3/src/distributions/cauchy.rs:33:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
rand-0.7.3/src/distributions/dirichlet.rs:52:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
rand-0.7.3/src/distributions/dirichlet.rs:52:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
rand-0.7.3/src/distributions/dirichlet.rs:64:32 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore"
|
rand-0.7.3/src/distributions/dirichlet.rs:64:32 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore"
|
||||||
rand-0.7.3/src/distributions/dirichlet.rs:65:23 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore"
|
rand-0.7.3/src/distributions/dirichlet.rs:65:23 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore"
|
||||||
rand-0.7.3/src/distributions/exponential.rs:76:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
rand-0.7.3/src/distributions/exponential.rs:76:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
rand-0.7.3/src/distributions/exponential.rs:76:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
rand-0.7.3/src/distributions/float.rs:73:1 clippy::module_name_repetitions "item name ends with its containing module's name"
|
rand-0.7.3/src/distributions/float.rs:73:1 clippy::module_name_repetitions "item name ends with its containing module's name"
|
||||||
rand-0.7.3/src/distributions/gamma.rs:13:5 clippy::enum_glob_use "usage of wildcard import for enum variants"
|
rand-0.7.3/src/distributions/gamma.rs:13:5 clippy::enum_glob_use "usage of wildcard import for enum variants"
|
||||||
rand-0.7.3/src/distributions/gamma.rs:14:5 clippy::enum_glob_use "usage of wildcard import for enum variants"
|
rand-0.7.3/src/distributions/gamma.rs:14:5 clippy::enum_glob_use "usage of wildcard import for enum variants"
|
||||||
rand-0.7.3/src/distributions/gamma.rs:189:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
rand-0.7.3/src/distributions/gamma.rs:189:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
rand-0.7.3/src/distributions/gamma.rs:189:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
rand-0.7.3/src/distributions/gamma.rs:230:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
rand-0.7.3/src/distributions/gamma.rs:230:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
rand-0.7.3/src/distributions/gamma.rs:230:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
rand-0.7.3/src/distributions/gamma.rs:259:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
rand-0.7.3/src/distributions/gamma.rs:259:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
rand-0.7.3/src/distributions/gamma.rs:259:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
rand-0.7.3/src/distributions/gamma.rs:287:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
rand-0.7.3/src/distributions/gamma.rs:287:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
rand-0.7.3/src/distributions/gamma.rs:287:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
rand-0.7.3/src/distributions/gamma.rs:90:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
rand-0.7.3/src/distributions/gamma.rs:90:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
rand-0.7.3/src/distributions/gamma.rs:90:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
rand-0.7.3/src/distributions/integer.rs:23:9 clippy::cast_possible_truncation "casting `u32` to `u8` may truncate the value"
|
rand-0.7.3/src/distributions/integer.rs:23:9 clippy::cast_possible_truncation "casting `u32` to `u8` may truncate the value"
|
||||||
rand-0.7.3/src/distributions/integer.rs:30:9 clippy::cast_possible_truncation "casting `u32` to `u16` may truncate the value"
|
rand-0.7.3/src/distributions/integer.rs:30:9 clippy::cast_possible_truncation "casting `u32` to `u16` may truncate the value"
|
||||||
|
@ -2226,7 +2192,6 @@ rand-0.7.3/src/distributions/normal.rs:47:25 clippy::unseparated_literal_suffix
|
||||||
rand-0.7.3/src/distributions/normal.rs:48:25 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore"
|
rand-0.7.3/src/distributions/normal.rs:48:25 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore"
|
||||||
rand-0.7.3/src/distributions/other.rs:89:9 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
|
rand-0.7.3/src/distributions/other.rs:89:9 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
|
||||||
rand-0.7.3/src/distributions/pareto.rs:32:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
rand-0.7.3/src/distributions/pareto.rs:32:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
rand-0.7.3/src/distributions/poisson.rs:35:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
rand-0.7.3/src/distributions/poisson.rs:35:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
rand-0.7.3/src/distributions/poisson.rs:35:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
rand-0.7.3/src/distributions/poisson.rs:87:30 clippy::cast_possible_truncation "casting `f64` to `u64` may truncate the value"
|
rand-0.7.3/src/distributions/poisson.rs:87:30 clippy::cast_possible_truncation "casting `f64` to `u64` may truncate the value"
|
||||||
rand-0.7.3/src/distributions/poisson.rs:87:30 clippy::cast_sign_loss "casting `f64` to `u64` may lose the sign of the value"
|
rand-0.7.3/src/distributions/poisson.rs:87:30 clippy::cast_sign_loss "casting `f64` to `u64` may lose the sign of the value"
|
||||||
|
@ -2316,6 +2281,7 @@ rand-0.7.3/src/rngs/adapter/reseeding.rs:112:5 clippy::inline_always "you have d
|
||||||
rand-0.7.3/src/rngs/adapter/reseeding.rs:117:5 clippy::inline_always "you have declared `#[inline(always)]` on `next_u64`. This is usually a bad idea"
|
rand-0.7.3/src/rngs/adapter/reseeding.rs:117:5 clippy::inline_always "you have declared `#[inline(always)]` on `next_u64`. This is usually a bad idea"
|
||||||
rand-0.7.3/src/rngs/adapter/reseeding.rs:198:13 clippy::cast_possible_wrap "casting `u64` to `i64` may wrap around the value"
|
rand-0.7.3/src/rngs/adapter/reseeding.rs:198:13 clippy::cast_possible_wrap "casting `u64` to `i64` may wrap around the value"
|
||||||
rand-0.7.3/src/rngs/adapter/reseeding.rs:231:9 clippy::cast_possible_wrap "casting `usize` to `isize` may wrap around the value"
|
rand-0.7.3/src/rngs/adapter/reseeding.rs:231:9 clippy::cast_possible_wrap "casting `usize` to `isize` may wrap around the value"
|
||||||
|
rand-0.7.3/src/rngs/adapter/reseeding.rs:249:13 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
rand-0.7.3/src/rngs/adapter/reseeding.rs:27:28 clippy::doc_markdown "you should put `ChaCha` between ticks in the documentation"
|
rand-0.7.3/src/rngs/adapter/reseeding.rs:27:28 clippy::doc_markdown "you should put `ChaCha` between ticks in the documentation"
|
||||||
rand-0.7.3/src/rngs/adapter/reseeding.rs:79:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
rand-0.7.3/src/rngs/adapter/reseeding.rs:79:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
||||||
rand-0.7.3/src/rngs/entropy.rs:24:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
rand-0.7.3/src/rngs/entropy.rs:24:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
||||||
|
@ -2344,7 +2310,6 @@ rand-0.7.3/src/seq/index.rs:139:13 clippy::enum_glob_use "usage of wildcard impo
|
||||||
rand-0.7.3/src/seq/index.rs:159:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
rand-0.7.3/src/seq/index.rs:159:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
||||||
rand-0.7.3/src/seq/index.rs:171:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
|
rand-0.7.3/src/seq/index.rs:171:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
|
||||||
rand-0.7.3/src/seq/index.rs:180:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
|
rand-0.7.3/src/seq/index.rs:180:13 clippy::enum_glob_use "usage of wildcard import for enum variants"
|
||||||
rand-0.7.3/src/seq/index.rs:213:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
rand-0.7.3/src/seq/index.rs:223:18 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
|
rand-0.7.3/src/seq/index.rs:223:18 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
|
||||||
rand-0.7.3/src/seq/index.rs:224:18 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
|
rand-0.7.3/src/seq/index.rs:224:18 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
|
||||||
rand-0.7.3/src/seq/index.rs:233:25 clippy::cast_precision_loss "casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)"
|
rand-0.7.3/src/seq/index.rs:233:25 clippy::cast_precision_loss "casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)"
|
||||||
|
@ -2369,14 +2334,12 @@ rand-0.7.3/src/seq/mod.rs:45:4 clippy::needless_doctest_main "needless `fn main`
|
||||||
rand-0.7.3/src/seq/mod.rs:527:26 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
|
rand-0.7.3/src/seq/mod.rs:527:26 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers"
|
||||||
rand_core-0.6.0/src/block.rs:117:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
rand_core-0.6.0/src/block.rs:117:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
||||||
rand_core-0.6.0/src/block.rs:153:5 clippy::inline_always "you have declared `#[inline(always)]` on `index`. This is usually a bad idea"
|
rand_core-0.6.0/src/block.rs:153:5 clippy::inline_always "you have declared `#[inline(always)]` on `index`. This is usually a bad idea"
|
||||||
rand_core-0.6.0/src/block.rs:168:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
rand_core-0.6.0/src/block.rs:230:5 clippy::inline_always "you have declared `#[inline(always)]` on `try_fill_bytes`. This is usually a bad idea"
|
rand_core-0.6.0/src/block.rs:230:5 clippy::inline_always "you have declared `#[inline(always)]` on `try_fill_bytes`. This is usually a bad idea"
|
||||||
rand_core-0.6.0/src/block.rs:240:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_seed`. This is usually a bad idea"
|
rand_core-0.6.0/src/block.rs:240:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_seed`. This is usually a bad idea"
|
||||||
rand_core-0.6.0/src/block.rs:245:5 clippy::inline_always "you have declared `#[inline(always)]` on `seed_from_u64`. This is usually a bad idea"
|
rand_core-0.6.0/src/block.rs:245:5 clippy::inline_always "you have declared `#[inline(always)]` on `seed_from_u64`. This is usually a bad idea"
|
||||||
rand_core-0.6.0/src/block.rs:250:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_rng`. This is usually a bad idea"
|
rand_core-0.6.0/src/block.rs:250:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_rng`. This is usually a bad idea"
|
||||||
rand_core-0.6.0/src/block.rs:280:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
rand_core-0.6.0/src/block.rs:280:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
||||||
rand_core-0.6.0/src/block.rs:319:5 clippy::inline_always "you have declared `#[inline(always)]` on `index`. This is usually a bad idea"
|
rand_core-0.6.0/src/block.rs:319:5 clippy::inline_always "you have declared `#[inline(always)]` on `index`. This is usually a bad idea"
|
||||||
rand_core-0.6.0/src/block.rs:335:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
rand_core-0.6.0/src/block.rs:405:5 clippy::inline_always "you have declared `#[inline(always)]` on `try_fill_bytes`. This is usually a bad idea"
|
rand_core-0.6.0/src/block.rs:405:5 clippy::inline_always "you have declared `#[inline(always)]` on `try_fill_bytes`. This is usually a bad idea"
|
||||||
rand_core-0.6.0/src/block.rs:415:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_seed`. This is usually a bad idea"
|
rand_core-0.6.0/src/block.rs:415:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_seed`. This is usually a bad idea"
|
||||||
rand_core-0.6.0/src/block.rs:420:5 clippy::inline_always "you have declared `#[inline(always)]` on `seed_from_u64`. This is usually a bad idea"
|
rand_core-0.6.0/src/block.rs:420:5 clippy::inline_always "you have declared `#[inline(always)]` on `seed_from_u64`. This is usually a bad idea"
|
||||||
|
@ -2386,8 +2349,6 @@ rand_core-0.6.0/src/block.rs:68:1 clippy::module_name_repetitions "item name sta
|
||||||
rand_core-0.6.0/src/error.rs:106:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
rand_core-0.6.0/src/error.rs:106:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
rand_core-0.6.0/src/error.rs:87:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
rand_core-0.6.0/src/error.rs:87:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
rand_core-0.6.0/src/error.rs:95:74 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
|
rand_core-0.6.0/src/error.rs:95:74 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value"
|
||||||
rand_core-0.6.0/src/le.rs:18:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
rand_core-0.6.0/src/le.rs:27:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
rand_core-0.6.0/src/lib.rs:179:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
rand_core-0.6.0/src/lib.rs:179:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
rand_core-0.6.0/src/lib.rs:301:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
rand_core-0.6.0/src/lib.rs:301:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute"
|
||||||
rand_core-0.6.0/src/lib.rs:303:26 clippy::unreadable_literal "long literal lacking separators"
|
rand_core-0.6.0/src/lib.rs:303:26 clippy::unreadable_literal "long literal lacking separators"
|
||||||
|
@ -2433,6 +2394,7 @@ rayon-1.5.0/src/iter/chain.rs:58:17 clippy::shadow_unrelated "`b` is being shado
|
||||||
rayon-1.5.0/src/iter/chain.rs:78:14 clippy::shadow_unrelated "`a` is being shadowed"
|
rayon-1.5.0/src/iter/chain.rs:78:14 clippy::shadow_unrelated "`a` is being shadowed"
|
||||||
rayon-1.5.0/src/iter/chain.rs:78:17 clippy::shadow_unrelated "`b` is being shadowed"
|
rayon-1.5.0/src/iter/chain.rs:78:17 clippy::shadow_unrelated "`b` is being shadowed"
|
||||||
rayon-1.5.0/src/iter/chain.rs:97:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
rayon-1.5.0/src/iter/chain.rs:97:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
|
rayon-1.5.0/src/iter/chunks.rs:29:9 clippy::inconsistent_struct_constructor "inconsistent struct constructor"
|
||||||
rayon-1.5.0/src/iter/chunks.rs:3:5 clippy::wildcard_imports "usage of wildcard import"
|
rayon-1.5.0/src/iter/chunks.rs:3:5 clippy::wildcard_imports "usage of wildcard import"
|
||||||
rayon-1.5.0/src/iter/chunks.rs:4:5 clippy::wildcard_imports "usage of wildcard import"
|
rayon-1.5.0/src/iter/chunks.rs:4:5 clippy::wildcard_imports "usage of wildcard import"
|
||||||
rayon-1.5.0/src/iter/chunks.rs:77:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
rayon-1.5.0/src/iter/chunks.rs:77:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope"
|
||||||
|
@ -2699,7 +2661,6 @@ regex-1.3.2/src/compile.rs:1040:38 clippy::cast_possible_truncation "casting `u1
|
||||||
regex-1.3.2/src/compile.rs:1051:25 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
|
regex-1.3.2/src/compile.rs:1051:25 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
|
||||||
regex-1.3.2/src/compile.rs:1071:8 clippy::cast_lossless "casting `u32` to `u64` may become silently lossy if you later change the type"
|
regex-1.3.2/src/compile.rs:1071:8 clippy::cast_lossless "casting `u32` to `u64` may become silently lossy if you later change the type"
|
||||||
regex-1.3.2/src/compile.rs:112:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
regex-1.3.2/src/compile.rs:112:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section"
|
||||||
regex-1.3.2/src/compile.rs:112:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
regex-1.3.2/src/compile.rs:154:30 clippy::redundant_closure_for_method_calls "redundant closure found"
|
regex-1.3.2/src/compile.rs:154:30 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
regex-1.3.2/src/compile.rs:156:30 clippy::redundant_closure_for_method_calls "redundant closure found"
|
regex-1.3.2/src/compile.rs:156:30 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
regex-1.3.2/src/compile.rs:185:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
|
regex-1.3.2/src/compile.rs:185:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
|
||||||
|
@ -3114,10 +3075,6 @@ regex-1.3.2/src/utf8.rs:85:19 clippy::cast_lossless "casting `u8` to `u32` may b
|
||||||
regex-1.3.2/src/utf8.rs:92:23 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
|
regex-1.3.2/src/utf8.rs:92:23 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
|
||||||
regex-1.3.2/src/utf8.rs:92:9 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
|
regex-1.3.2/src/utf8.rs:92:9 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
|
||||||
regex-1.3.2/src/utf8.rs:97:16 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
|
regex-1.3.2/src/utf8.rs:97:16 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four"
|
||||||
ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:30:27 clippy::match_same_arms "this `match` has identical arm bodies"
|
|
||||||
ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:30:27 clippy::match_same_arms "this `match` has identical arm bodies"
|
|
||||||
ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:30:27 clippy::match_same_arms "this `match` has identical arm bodies"
|
|
||||||
ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:30:27 clippy::match_same_arms "this `match` has identical arm bodies"
|
|
||||||
ripgrep-12.1.1/build.rs:133:19 clippy::option_as_ref_deref "called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `githash.as_deref()` instead"
|
ripgrep-12.1.1/build.rs:133:19 clippy::option_as_ref_deref "called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `githash.as_deref()` instead"
|
||||||
ripgrep-12.1.1/build.rs:18:18 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
ripgrep-12.1.1/build.rs:18:18 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
||||||
ripgrep-12.1.1/build.rs:225:14 clippy::redundant_closure_for_method_calls "redundant closure found"
|
ripgrep-12.1.1/build.rs:225:14 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
|
@ -3171,6 +3128,7 @@ ripgrep-12.1.1/crates/core/args.rs:1524:5 clippy::unnecessary_wraps "this functi
|
||||||
ripgrep-12.1.1/crates/core/args.rs:1635:14 clippy::doc_markdown "you should put `values_of_lossy` between ticks in the documentation"
|
ripgrep-12.1.1/crates/core/args.rs:1635:14 clippy::doc_markdown "you should put `values_of_lossy` between ticks in the documentation"
|
||||||
ripgrep-12.1.1/crates/core/args.rs:1693:41 clippy::redundant_closure_for_method_calls "redundant closure found"
|
ripgrep-12.1.1/crates/core/args.rs:1693:41 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
ripgrep-12.1.1/crates/core/args.rs:1770:17 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
|
ripgrep-12.1.1/crates/core/args.rs:1770:17 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
|
||||||
|
ripgrep-12.1.1/crates/core/args.rs:1829:5 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
ripgrep-12.1.1/crates/core/args.rs:287:13 clippy::similar_names "binding's name is too similar to existing binding"
|
ripgrep-12.1.1/crates/core/args.rs:287:13 clippy::similar_names "binding's name is too similar to existing binding"
|
||||||
ripgrep-12.1.1/crates/core/args.rs:33:1 clippy::single_component_path_imports "this import is redundant"
|
ripgrep-12.1.1/crates/core/args.rs:33:1 clippy::single_component_path_imports "this import is redundant"
|
||||||
ripgrep-12.1.1/crates/core/args.rs:34:1 clippy::single_component_path_imports "this import is redundant"
|
ripgrep-12.1.1/crates/core/args.rs:34:1 clippy::single_component_path_imports "this import is redundant"
|
||||||
|
@ -3189,6 +3147,8 @@ ripgrep-12.1.1/crates/core/config.rs:58:6 clippy::type_complexity "very complex
|
||||||
ripgrep-12.1.1/crates/core/config.rs:79:6 clippy::type_complexity "very complex type used. Consider factoring parts into `type` definitions"
|
ripgrep-12.1.1/crates/core/config.rs:79:6 clippy::type_complexity "very complex type used. Consider factoring parts into `type` definitions"
|
||||||
ripgrep-12.1.1/crates/core/logger.rs:11:30 clippy::doc_markdown "you should put `max_level` between ticks in the documentation"
|
ripgrep-12.1.1/crates/core/logger.rs:11:30 clippy::doc_markdown "you should put `max_level` between ticks in the documentation"
|
||||||
ripgrep-12.1.1/crates/core/logger.rs:15:16 clippy::redundant_static_lifetimes "constants have by default a `'static` lifetime"
|
ripgrep-12.1.1/crates/core/logger.rs:15:16 clippy::redundant_static_lifetimes "constants have by default a `'static` lifetime"
|
||||||
|
ripgrep-12.1.1/crates/core/main.rs:114:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
|
ripgrep-12.1.1/crates/core/main.rs:189:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
ripgrep-12.1.1/crates/core/main.rs:55:19 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
|
ripgrep-12.1.1/crates/core/main.rs:55:19 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
|
||||||
ripgrep-12.1.1/crates/core/main.rs:56:9 clippy::enum_glob_use "usage of wildcard import for enum variants"
|
ripgrep-12.1.1/crates/core/main.rs:56:9 clippy::enum_glob_use "usage of wildcard import for enum variants"
|
||||||
ripgrep-12.1.1/crates/core/messages.rs:46:1 clippy::module_name_repetitions "item name ends with its containing module's name"
|
ripgrep-12.1.1/crates/core/messages.rs:46:1 clippy::module_name_repetitions "item name ends with its containing module's name"
|
||||||
|
@ -3216,19 +3176,18 @@ ripgrep-12.1.1/crates/core/search.rs:533:36 clippy::cast_lossless "casting `u32`
|
||||||
ripgrep-12.1.1/crates/core/search.rs:533:5 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
|
ripgrep-12.1.1/crates/core/search.rs:533:5 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)"
|
||||||
ripgrep-12.1.1/crates/core/subject.rs:20:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
ripgrep-12.1.1/crates/core/subject.rs:20:1 clippy::module_name_repetitions "item name starts with its containing module's name"
|
||||||
ripgrep-12.1.1/crates/core/subject.rs:4:1 clippy::single_component_path_imports "this import is redundant"
|
ripgrep-12.1.1/crates/core/subject.rs:4:1 clippy::single_component_path_imports "this import is redundant"
|
||||||
|
serde-1.0.118/src/de/mod.rs:1592:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
|
serde-1.0.118/src/de/mod.rs:1616:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
|
serde-1.0.118/src/de/mod.rs:1627:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
|
serde-1.0.118/src/de/mod.rs:1638:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
|
serde-1.0.118/src/de/mod.rs:1649:9 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
|
serde-1.0.118/src/de/mod.rs:952:13 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
|
serde-1.0.118/src/de/mod.rs:986:13 clippy::let_underscore_drop "non-binding `let` on a type that implements `Drop`"
|
||||||
syn-1.0.54/build.rs:1:null clippy::cargo_common_metadata "package `syn` is missing `package.keywords` metadata"
|
syn-1.0.54/build.rs:1:null clippy::cargo_common_metadata "package `syn` is missing `package.keywords` metadata"
|
||||||
syn-1.0.54/build.rs:1:null clippy::multiple_crate_versions "could not read cargo metadata: `cargo metadata` exited with an error: Downloading crates ...\n Downloaded syn-test-suite v0.0.0\nerror: failed to verify the checksum of `syn-test-suite v0.0.0`"
|
|
||||||
syn-1.0.54/src/generics.rs:174:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
syn-1.0.54/src/lib.rs:1:null clippy::cargo_common_metadata "package `syn` is missing `package.keywords` metadata"
|
syn-1.0.54/src/lib.rs:1:null clippy::cargo_common_metadata "package `syn` is missing `package.keywords` metadata"
|
||||||
syn-1.0.54/src/lib.rs:1:null clippy::multiple_crate_versions "could not read cargo metadata: `cargo metadata` exited with an error: Downloading crates ...\n Downloaded syn-test-suite v0.0.0\nerror: failed to verify the checksum of `syn-test-suite v0.0.0`"
|
|
||||||
syn-1.0.54/src/lit.rs:1397:40 clippy::redundant_else "redundant else block"
|
syn-1.0.54/src/lit.rs:1397:40 clippy::redundant_else "redundant else block"
|
||||||
syn-1.0.54/src/lit.rs:1405:28 clippy::redundant_else "redundant else block"
|
syn-1.0.54/src/lit.rs:1405:28 clippy::redundant_else "redundant else block"
|
||||||
syn-1.0.54/src/lit.rs:1485:32 clippy::redundant_else "redundant else block"
|
syn-1.0.54/src/lit.rs:1485:32 clippy::redundant_else "redundant else block"
|
||||||
syn-1.0.54/src/lit.rs:343:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
syn-1.0.54/src/lit.rs:437:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
syn-1.0.54/src/lit.rs:916:9 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
syn-1.0.54/src/token.rs:974:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
syn-1.0.54/src/token.rs:996:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section"
|
|
||||||
unicode-xid-0.2.1/src/lib.rs:1:null clippy::cargo_common_metadata "package `unicode-xid` is missing `package.categories` metadata"
|
unicode-xid-0.2.1/src/lib.rs:1:null clippy::cargo_common_metadata "package `unicode-xid` is missing `package.categories` metadata"
|
||||||
unicode-xid-0.2.1/src/lib.rs:56:11 clippy::upper_case_acronyms "name `UnicodeXID` contains a capitalized acronym"
|
unicode-xid-0.2.1/src/lib.rs:56:11 clippy::upper_case_acronyms "name `UnicodeXID` contains a capitalized acronym"
|
||||||
unicode-xid-0.2.1/src/lib.rs:57:64 clippy::doc_markdown "you should put `XID_Start` between ticks in the documentation"
|
unicode-xid-0.2.1/src/lib.rs:57:64 clippy::doc_markdown "you should put `XID_Start` between ticks in the documentation"
|
||||||
|
@ -3248,7 +3207,6 @@ xsv-0.13.0/src/cmd/cat.rs:7:16 clippy::redundant_static_lifetimes "statics have
|
||||||
xsv-0.13.0/src/cmd/count.rs:32:9 clippy::similar_names "binding's name is too similar to existing binding"
|
xsv-0.13.0/src/cmd/count.rs:32:9 clippy::similar_names "binding's name is too similar to existing binding"
|
||||||
xsv-0.13.0/src/cmd/count.rs:38:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
xsv-0.13.0/src/cmd/count.rs:38:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
||||||
xsv-0.13.0/src/cmd/count.rs:42:33 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
|
xsv-0.13.0/src/cmd/count.rs:42:33 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore"
|
||||||
xsv-0.13.0/src/cmd/count.rs:50:5 clippy::unit_arg "passing a unit value to a function"
|
|
||||||
xsv-0.13.0/src/cmd/count.rs:7:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
|
xsv-0.13.0/src/cmd/count.rs:7:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
|
||||||
xsv-0.13.0/src/cmd/fixlengths.rs:45:9 clippy::similar_names "binding's name is too similar to existing binding"
|
xsv-0.13.0/src/cmd/fixlengths.rs:45:9 clippy::similar_names "binding's name is too similar to existing binding"
|
||||||
xsv-0.13.0/src/cmd/fixlengths.rs:50:18 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
xsv-0.13.0/src/cmd/fixlengths.rs:50:18 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`"
|
||||||
|
@ -3324,7 +3282,7 @@ xsv-0.13.0/src/cmd/sort.rs:48:9 clippy::similar_names "binding's name is too sim
|
||||||
xsv-0.13.0/src/cmd/sort.rs:91:14 clippy::explicit_into_iter_loop "it is more concise to loop over containers instead of using explicit iteration methods"
|
xsv-0.13.0/src/cmd/sort.rs:91:14 clippy::explicit_into_iter_loop "it is more concise to loop over containers instead of using explicit iteration methods"
|
||||||
xsv-0.13.0/src/cmd/split.rs:14:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
|
xsv-0.13.0/src/cmd/split.rs:14:16 clippy::redundant_static_lifetimes "statics have by default a `'static` lifetime"
|
||||||
xsv-0.13.0/src/cmd/split.rs:61:9 clippy::similar_names "binding's name is too similar to existing binding"
|
xsv-0.13.0/src/cmd/split.rs:61:9 clippy::similar_names "binding's name is too similar to existing binding"
|
||||||
xsv-0.13.0/src/cmd/split.rs:94:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`"
|
xsv-0.13.0/src/cmd/split.rs:94:5 clippy::unnecessary_wraps "this function's return value is unnecessary"
|
||||||
xsv-0.13.0/src/cmd/split.rs:96:14 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
|
xsv-0.13.0/src/cmd/split.rs:96:14 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body"
|
||||||
xsv-0.13.0/src/cmd/split.rs:99:13 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
|
xsv-0.13.0/src/cmd/split.rs:99:13 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers"
|
||||||
xsv-0.13.0/src/cmd/stats.rs:110:36 clippy::redundant_closure_for_method_calls "redundant closure found"
|
xsv-0.13.0/src/cmd/stats.rs:110:36 clippy::redundant_closure_for_method_calls "redundant closure found"
|
||||||
|
@ -3438,14 +3396,12 @@ clippy::redundant_slicing 1
|
||||||
clippy::same_item_push 1
|
clippy::same_item_push 1
|
||||||
clippy::should_implement_trait 1
|
clippy::should_implement_trait 1
|
||||||
clippy::stable_sort_primitive 1
|
clippy::stable_sort_primitive 1
|
||||||
clippy::unit_arg 1
|
|
||||||
clippy::unnecessary_lazy_evaluations 1
|
clippy::unnecessary_lazy_evaluations 1
|
||||||
clippy::unsafe_derive_deserialize 1
|
clippy::unsafe_derive_deserialize 1
|
||||||
clippy::used_underscore_binding 1
|
clippy::used_underscore_binding 1
|
||||||
clippy::verbose_bit_mask 1
|
clippy::verbose_bit_mask 1
|
||||||
clippy::while_let_on_iterator 1
|
clippy::while_let_on_iterator 1
|
||||||
clippy::comparison_to_empty 2
|
clippy::comparison_to_empty 2
|
||||||
clippy::derive_hash_xor_eq 2
|
|
||||||
clippy::expl_impl_clone_on_copy 2
|
clippy::expl_impl_clone_on_copy 2
|
||||||
clippy::filter_map 2
|
clippy::filter_map 2
|
||||||
clippy::len_zero 2
|
clippy::len_zero 2
|
||||||
|
@ -3463,10 +3419,10 @@ clippy::write_with_newline 2
|
||||||
clippy::filter_map_next 3
|
clippy::filter_map_next 3
|
||||||
clippy::fn_params_excessive_bools 3
|
clippy::fn_params_excessive_bools 3
|
||||||
clippy::if_same_then_else 3
|
clippy::if_same_then_else 3
|
||||||
|
clippy::inconsistent_struct_constructor 3
|
||||||
clippy::mut_mut 3
|
clippy::mut_mut 3
|
||||||
clippy::ptr_arg 3
|
clippy::ptr_arg 3
|
||||||
clippy::zero_ptr 3
|
clippy::zero_ptr 3
|
||||||
clippy::let_underscore_drop 4
|
|
||||||
clippy::too_many_arguments 4
|
clippy::too_many_arguments 4
|
||||||
clippy::explicit_iter_loop 5
|
clippy::explicit_iter_loop 5
|
||||||
clippy::field_reassign_with_default 5
|
clippy::field_reassign_with_default 5
|
||||||
|
@ -3488,11 +3444,11 @@ clippy::range_plus_one 7
|
||||||
clippy::invalid_upcast_comparisons 8
|
clippy::invalid_upcast_comparisons 8
|
||||||
clippy::needless_question_mark 8
|
clippy::needless_question_mark 8
|
||||||
clippy::wrong_self_convention 8
|
clippy::wrong_self_convention 8
|
||||||
|
clippy::multiple_crate_versions 9
|
||||||
clippy::manual_range_contains 10
|
clippy::manual_range_contains 10
|
||||||
clippy::match_wildcard_for_single_variants 10
|
clippy::match_wildcard_for_single_variants 10
|
||||||
clippy::missing_safety_doc 10
|
clippy::missing_safety_doc 10
|
||||||
clippy::needless_doctest_main 10
|
clippy::needless_doctest_main 10
|
||||||
clippy::multiple_crate_versions 11
|
|
||||||
clippy::needless_lifetimes 12
|
clippy::needless_lifetimes 12
|
||||||
clippy::cargo_common_metadata 13
|
clippy::cargo_common_metadata 13
|
||||||
clippy::shadow_unrelated 13
|
clippy::shadow_unrelated 13
|
||||||
|
@ -3511,6 +3467,7 @@ clippy::struct_excessive_bools 20
|
||||||
clippy::redundant_static_lifetimes 21
|
clippy::redundant_static_lifetimes 21
|
||||||
clippy::default_trait_access 22
|
clippy::default_trait_access 22
|
||||||
clippy::cast_lossless 23
|
clippy::cast_lossless 23
|
||||||
|
clippy::let_underscore_drop 23
|
||||||
clippy::trivially_copy_pass_by_ref 26
|
clippy::trivially_copy_pass_by_ref 26
|
||||||
clippy::redundant_else 29
|
clippy::redundant_else 29
|
||||||
clippy::too_many_lines 32
|
clippy::too_many_lines 32
|
||||||
|
@ -3519,11 +3476,11 @@ clippy::enum_glob_use 40
|
||||||
clippy::unseparated_literal_suffix 41
|
clippy::unseparated_literal_suffix 41
|
||||||
clippy::cast_precision_loss 44
|
clippy::cast_precision_loss 44
|
||||||
clippy::single_match_else 45
|
clippy::single_match_else 45
|
||||||
|
clippy::missing_panics_doc 54
|
||||||
clippy::inline_always 59
|
clippy::inline_always 59
|
||||||
clippy::match_same_arms 65
|
clippy::match_same_arms 60
|
||||||
clippy::similar_names 78
|
clippy::similar_names 78
|
||||||
clippy::cast_possible_truncation 95
|
clippy::cast_possible_truncation 95
|
||||||
clippy::missing_panics_doc 108
|
|
||||||
clippy::redundant_field_names 111
|
clippy::redundant_field_names 111
|
||||||
clippy::redundant_closure_for_method_calls 135
|
clippy::redundant_closure_for_method_calls 135
|
||||||
clippy::items_after_statements 139
|
clippy::items_after_statements 139
|
||||||
|
@ -3533,3 +3490,4 @@ clippy::doc_markdown 178
|
||||||
clippy::missing_errors_doc 343
|
clippy::missing_errors_doc 343
|
||||||
clippy::unreadable_literal 365
|
clippy::unreadable_literal 365
|
||||||
clippy::must_use_candidate 565
|
clippy::must_use_candidate 565
|
||||||
|
ICEs:
|
||||||
|
|
|
@ -66,8 +66,8 @@ fn third_party_crates() -> String {
|
||||||
fn default_config() -> compiletest::Config {
|
fn default_config() -> compiletest::Config {
|
||||||
let mut config = compiletest::Config::default();
|
let mut config = compiletest::Config::default();
|
||||||
|
|
||||||
if let Ok(name) = env::var("TESTNAME") {
|
if let Ok(filters) = env::var("TESTNAME") {
|
||||||
config.filter = Some(name);
|
config.filters = filters.split(',').map(std::string::ToString::to_string).collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(path) = option_env!("RUSTC_LIB_PATH") {
|
if let Some(path) = option_env!("RUSTC_LIB_PATH") {
|
||||||
|
@ -167,7 +167,7 @@ fn run_ui_toml(config: &mut compiletest::Config) {
|
||||||
fn run_ui_cargo(config: &mut compiletest::Config) {
|
fn run_ui_cargo(config: &mut compiletest::Config) {
|
||||||
fn run_tests(
|
fn run_tests(
|
||||||
config: &compiletest::Config,
|
config: &compiletest::Config,
|
||||||
filter: &Option<String>,
|
filters: &[String],
|
||||||
mut tests: Vec<tester::TestDescAndFn>,
|
mut tests: Vec<tester::TestDescAndFn>,
|
||||||
) -> Result<bool, io::Error> {
|
) -> Result<bool, io::Error> {
|
||||||
let mut result = true;
|
let mut result = true;
|
||||||
|
@ -181,9 +181,10 @@ fn run_ui_cargo(config: &mut compiletest::Config) {
|
||||||
|
|
||||||
// Use the filter if provided
|
// Use the filter if provided
|
||||||
let dir_path = dir.path();
|
let dir_path = dir.path();
|
||||||
match &filter {
|
for filter in filters {
|
||||||
Some(name) if !dir_path.ends_with(name) => continue,
|
if !dir_path.ends_with(filter) {
|
||||||
_ => {},
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for case in fs::read_dir(&dir_path)? {
|
for case in fs::read_dir(&dir_path)? {
|
||||||
|
@ -243,8 +244,7 @@ fn run_ui_cargo(config: &mut compiletest::Config) {
|
||||||
|
|
||||||
let current_dir = env::current_dir().unwrap();
|
let current_dir = env::current_dir().unwrap();
|
||||||
let conf_dir = var("CLIPPY_CONF_DIR").unwrap_or_default();
|
let conf_dir = var("CLIPPY_CONF_DIR").unwrap_or_default();
|
||||||
let filter = env::var("TESTNAME").ok();
|
let res = run_tests(&config, &config.filters, tests);
|
||||||
let res = run_tests(&config, &filter, tests);
|
|
||||||
env::set_current_dir(current_dir).unwrap();
|
env::set_current_dir(current_dir).unwrap();
|
||||||
set_var("CLIPPY_CONF_DIR", conf_dir);
|
set_var("CLIPPY_CONF_DIR", conf_dir);
|
||||||
|
|
||||||
|
|
|
@ -41,3 +41,15 @@ pub fn derive_foo(_input: TokenStream) -> TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(StructAUseSelf)]
|
||||||
|
pub fn derive_use_self(_input: TokenStream) -> proc_macro::TokenStream {
|
||||||
|
quote! {
|
||||||
|
struct A;
|
||||||
|
impl A {
|
||||||
|
fn new() -> A {
|
||||||
|
A
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -44,4 +44,13 @@ fn macro_in_closure() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
#[rustfmt::skip]
|
||||||
|
fn main() {
|
||||||
|
let mut range = 0..10;
|
||||||
|
range.all(|i| {i < 10} );
|
||||||
|
|
||||||
|
let v = vec![1, 2, 3];
|
||||||
|
if v.into_iter().any(|x| {x == 4}) {
|
||||||
|
println!("contains 4!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -65,4 +65,13 @@ fn main() {
|
||||||
else {
|
else {
|
||||||
println!("!")
|
println!("!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if x == "hello" {
|
||||||
|
print!("Hello ");
|
||||||
|
} else {
|
||||||
|
#[cfg(not(roflol))]
|
||||||
|
if y == "world" {
|
||||||
|
println!("world!")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,4 +79,13 @@ fn main() {
|
||||||
println!("!")
|
println!("!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if x == "hello" {
|
||||||
|
print!("Hello ");
|
||||||
|
} else {
|
||||||
|
#[cfg(not(roflol))]
|
||||||
|
if y == "world" {
|
||||||
|
println!("world!")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,4 +138,11 @@ fn main() {
|
||||||
|
|
||||||
// Fix #5962
|
// Fix #5962
|
||||||
if matches!(true, true) && matches!(true, true) {}
|
if matches!(true, true) && matches!(true, true) {}
|
||||||
|
|
||||||
|
if true {
|
||||||
|
#[cfg(not(teehee))]
|
||||||
|
if true {
|
||||||
|
println!("Hello world!");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,4 +154,11 @@ fn main() {
|
||||||
if matches!(true, true) {
|
if matches!(true, true) {
|
||||||
if matches!(true, true) {}
|
if matches!(true, true) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if true {
|
||||||
|
#[cfg(not(teehee))]
|
||||||
|
if true {
|
||||||
|
println!("Hello world!");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,6 +232,14 @@ fn negative_cases(res_opt: Result<Option<u32>, String>, res_res: Result<Result<u
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let _: &dyn std::any::Any = match &Some(Some(1)) {
|
||||||
|
Some(e) => match e {
|
||||||
|
Some(e) => e,
|
||||||
|
e => e,
|
||||||
|
},
|
||||||
|
// else branch looks the same but the binding is different
|
||||||
|
e => e,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make<T>() -> T {
|
fn make<T>() -> T {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match.rs:7:20
|
--> $DIR/collapsible_match.rs:7:20
|
||||||
|
|
|
|
||||||
LL | Ok(val) => match val {
|
LL | Ok(val) => match val {
|
||||||
|
@ -9,15 +9,15 @@ LL | | },
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::collapsible-match` implied by `-D warnings`
|
= note: `-D clippy::collapsible-match` implied by `-D warnings`
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match.rs:7:12
|
--> $DIR/collapsible_match.rs:7:12
|
||||||
|
|
|
|
||||||
LL | Ok(val) => match val {
|
LL | Ok(val) => match val {
|
||||||
| ^^^ Replace this binding
|
| ^^^ replace this binding
|
||||||
LL | Some(n) => foo(n),
|
LL | Some(n) => foo(n),
|
||||||
| ^^^^^^^ with this pattern
|
| ^^^^^^^ with this pattern
|
||||||
|
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match.rs:16:20
|
--> $DIR/collapsible_match.rs:16:20
|
||||||
|
|
|
|
||||||
LL | Ok(val) => match val {
|
LL | Ok(val) => match val {
|
||||||
|
@ -27,15 +27,15 @@ LL | | _ => return,
|
||||||
LL | | },
|
LL | | },
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match.rs:16:12
|
--> $DIR/collapsible_match.rs:16:12
|
||||||
|
|
|
|
||||||
LL | Ok(val) => match val {
|
LL | Ok(val) => match val {
|
||||||
| ^^^ Replace this binding
|
| ^^^ replace this binding
|
||||||
LL | Some(n) => foo(n),
|
LL | Some(n) => foo(n),
|
||||||
| ^^^^^^^ with this pattern
|
| ^^^^^^^ with this pattern
|
||||||
|
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match.rs:25:9
|
--> $DIR/collapsible_match.rs:25:9
|
||||||
|
|
|
|
||||||
LL | / if let Some(n) = val {
|
LL | / if let Some(n) = val {
|
||||||
|
@ -43,15 +43,15 @@ LL | | take(n);
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match.rs:24:15
|
--> $DIR/collapsible_match.rs:24:15
|
||||||
|
|
|
|
||||||
LL | if let Ok(val) = res_opt {
|
LL | if let Ok(val) = res_opt {
|
||||||
| ^^^ Replace this binding
|
| ^^^ replace this binding
|
||||||
LL | if let Some(n) = val {
|
LL | if let Some(n) = val {
|
||||||
| ^^^^^^^ with this pattern
|
| ^^^^^^^ with this pattern
|
||||||
|
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match.rs:32:9
|
--> $DIR/collapsible_match.rs:32:9
|
||||||
|
|
|
|
||||||
LL | / if let Some(n) = val {
|
LL | / if let Some(n) = val {
|
||||||
|
@ -61,15 +61,15 @@ LL | | return;
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match.rs:31:15
|
--> $DIR/collapsible_match.rs:31:15
|
||||||
|
|
|
|
||||||
LL | if let Ok(val) = res_opt {
|
LL | if let Ok(val) = res_opt {
|
||||||
| ^^^ Replace this binding
|
| ^^^ replace this binding
|
||||||
LL | if let Some(n) = val {
|
LL | if let Some(n) = val {
|
||||||
| ^^^^^^^ with this pattern
|
| ^^^^^^^ with this pattern
|
||||||
|
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match.rs:43:9
|
--> $DIR/collapsible_match.rs:43:9
|
||||||
|
|
|
|
||||||
LL | / match val {
|
LL | / match val {
|
||||||
|
@ -78,16 +78,16 @@ LL | | _ => (),
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match.rs:42:15
|
--> $DIR/collapsible_match.rs:42:15
|
||||||
|
|
|
|
||||||
LL | if let Ok(val) = res_opt {
|
LL | if let Ok(val) = res_opt {
|
||||||
| ^^^ Replace this binding
|
| ^^^ replace this binding
|
||||||
LL | match val {
|
LL | match val {
|
||||||
LL | Some(n) => foo(n),
|
LL | Some(n) => foo(n),
|
||||||
| ^^^^^^^ with this pattern
|
| ^^^^^^^ with this pattern
|
||||||
|
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match.rs:52:13
|
--> $DIR/collapsible_match.rs:52:13
|
||||||
|
|
|
|
||||||
LL | / if let Some(n) = val {
|
LL | / if let Some(n) = val {
|
||||||
|
@ -95,15 +95,15 @@ LL | | take(n);
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____________^
|
| |_____________^
|
||||||
|
|
|
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match.rs:51:12
|
--> $DIR/collapsible_match.rs:51:12
|
||||||
|
|
|
|
||||||
LL | Ok(val) => {
|
LL | Ok(val) => {
|
||||||
| ^^^ Replace this binding
|
| ^^^ replace this binding
|
||||||
LL | if let Some(n) = val {
|
LL | if let Some(n) = val {
|
||||||
| ^^^^^^^ with this pattern
|
| ^^^^^^^ with this pattern
|
||||||
|
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match.rs:61:9
|
--> $DIR/collapsible_match.rs:61:9
|
||||||
|
|
|
|
||||||
LL | / match val {
|
LL | / match val {
|
||||||
|
@ -112,16 +112,16 @@ LL | | _ => return,
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match.rs:60:15
|
--> $DIR/collapsible_match.rs:60:15
|
||||||
|
|
|
|
||||||
LL | if let Ok(val) = res_opt {
|
LL | if let Ok(val) = res_opt {
|
||||||
| ^^^ Replace this binding
|
| ^^^ replace this binding
|
||||||
LL | match val {
|
LL | match val {
|
||||||
LL | Some(n) => foo(n),
|
LL | Some(n) => foo(n),
|
||||||
| ^^^^^^^ with this pattern
|
| ^^^^^^^ with this pattern
|
||||||
|
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match.rs:72:13
|
--> $DIR/collapsible_match.rs:72:13
|
||||||
|
|
|
|
||||||
LL | / if let Some(n) = val {
|
LL | / if let Some(n) = val {
|
||||||
|
@ -131,15 +131,15 @@ LL | | return;
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____________^
|
| |_____________^
|
||||||
|
|
|
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match.rs:71:12
|
--> $DIR/collapsible_match.rs:71:12
|
||||||
|
|
|
|
||||||
LL | Ok(val) => {
|
LL | Ok(val) => {
|
||||||
| ^^^ Replace this binding
|
| ^^^ replace this binding
|
||||||
LL | if let Some(n) = val {
|
LL | if let Some(n) = val {
|
||||||
| ^^^^^^^ with this pattern
|
| ^^^^^^^ with this pattern
|
||||||
|
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match.rs:83:20
|
--> $DIR/collapsible_match.rs:83:20
|
||||||
|
|
|
|
||||||
LL | Ok(val) => match val {
|
LL | Ok(val) => match val {
|
||||||
|
@ -149,15 +149,15 @@ LL | | None => return,
|
||||||
LL | | },
|
LL | | },
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match.rs:83:12
|
--> $DIR/collapsible_match.rs:83:12
|
||||||
|
|
|
|
||||||
LL | Ok(val) => match val {
|
LL | Ok(val) => match val {
|
||||||
| ^^^ Replace this binding
|
| ^^^ replace this binding
|
||||||
LL | Some(n) => foo(n),
|
LL | Some(n) => foo(n),
|
||||||
| ^^^^^^^ with this pattern
|
| ^^^^^^^ with this pattern
|
||||||
|
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match.rs:92:22
|
--> $DIR/collapsible_match.rs:92:22
|
||||||
|
|
|
|
||||||
LL | Some(val) => match val {
|
LL | Some(val) => match val {
|
||||||
|
@ -167,11 +167,11 @@ LL | | _ => return,
|
||||||
LL | | },
|
LL | | },
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match.rs:92:14
|
--> $DIR/collapsible_match.rs:92:14
|
||||||
|
|
|
|
||||||
LL | Some(val) => match val {
|
LL | Some(val) => match val {
|
||||||
| ^^^ Replace this binding
|
| ^^^ replace this binding
|
||||||
LL | Some(n) => foo(n),
|
LL | Some(n) => foo(n),
|
||||||
| ^^^^^^^ with this pattern
|
| ^^^^^^^ with this pattern
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match2.rs:8:34
|
--> $DIR/collapsible_match2.rs:8:34
|
||||||
|
|
|
|
||||||
LL | Ok(val) if make() => match val {
|
LL | Ok(val) if make() => match val {
|
||||||
|
@ -9,15 +9,15 @@ LL | | },
|
||||||
| |_____________^
|
| |_____________^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::collapsible-match` implied by `-D warnings`
|
= note: `-D clippy::collapsible-match` implied by `-D warnings`
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match2.rs:8:16
|
--> $DIR/collapsible_match2.rs:8:16
|
||||||
|
|
|
|
||||||
LL | Ok(val) if make() => match val {
|
LL | Ok(val) if make() => match val {
|
||||||
| ^^^ Replace this binding
|
| ^^^ replace this binding
|
||||||
LL | Some(n) => foo(n),
|
LL | Some(n) => foo(n),
|
||||||
| ^^^^^^^ with this pattern
|
| ^^^^^^^ with this pattern
|
||||||
|
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match2.rs:15:24
|
--> $DIR/collapsible_match2.rs:15:24
|
||||||
|
|
|
|
||||||
LL | Ok(val) => match val {
|
LL | Ok(val) => match val {
|
||||||
|
@ -27,15 +27,15 @@ LL | | _ => return,
|
||||||
LL | | },
|
LL | | },
|
||||||
| |_____________^
|
| |_____________^
|
||||||
|
|
|
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match2.rs:15:16
|
--> $DIR/collapsible_match2.rs:15:16
|
||||||
|
|
|
|
||||||
LL | Ok(val) => match val {
|
LL | Ok(val) => match val {
|
||||||
| ^^^ Replace this binding
|
| ^^^ replace this binding
|
||||||
LL | Some(n) => foo(n),
|
LL | Some(n) => foo(n),
|
||||||
| ^^^^^^^ with this pattern
|
| ^^^^^^^ with this pattern
|
||||||
|
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match2.rs:29:29
|
--> $DIR/collapsible_match2.rs:29:29
|
||||||
|
|
|
|
||||||
LL | $pat => match $e {
|
LL | $pat => match $e {
|
||||||
|
@ -48,16 +48,16 @@ LL | | },
|
||||||
LL | mac!(res_opt => Ok(val), val => Some(n), foo(n));
|
LL | mac!(res_opt => Ok(val), val => Some(n), foo(n));
|
||||||
| ------------------------------------------------- in this macro invocation
|
| ------------------------------------------------- in this macro invocation
|
||||||
|
|
|
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match2.rs:41:28
|
--> $DIR/collapsible_match2.rs:41:28
|
||||||
|
|
|
|
||||||
LL | mac!(res_opt => Ok(val), val => Some(n), foo(n));
|
LL | mac!(res_opt => Ok(val), val => Some(n), foo(n));
|
||||||
| ^^^ ^^^^^^^ with this pattern
|
| ^^^ ^^^^^^^ with this pattern
|
||||||
| |
|
| |
|
||||||
| Replace this binding
|
| replace this binding
|
||||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match2.rs:46:20
|
--> $DIR/collapsible_match2.rs:46:20
|
||||||
|
|
|
|
||||||
LL | Some(s) => match *s {
|
LL | Some(s) => match *s {
|
||||||
|
@ -67,15 +67,15 @@ LL | | _ => (),
|
||||||
LL | | },
|
LL | | },
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match2.rs:46:14
|
--> $DIR/collapsible_match2.rs:46:14
|
||||||
|
|
|
|
||||||
LL | Some(s) => match *s {
|
LL | Some(s) => match *s {
|
||||||
| ^ Replace this binding
|
| ^ replace this binding
|
||||||
LL | [n] => foo(n),
|
LL | [n] => foo(n),
|
||||||
| ^^^ with this pattern
|
| ^^^ with this pattern
|
||||||
|
|
||||||
error: Unnecessary nested match
|
error: unnecessary nested match
|
||||||
--> $DIR/collapsible_match2.rs:55:24
|
--> $DIR/collapsible_match2.rs:55:24
|
||||||
|
|
|
|
||||||
LL | Some(ref s) => match &*s {
|
LL | Some(ref s) => match &*s {
|
||||||
|
@ -85,11 +85,11 @@ LL | | _ => (),
|
||||||
LL | | },
|
LL | | },
|
||||||
| |_________^
|
| |_________^
|
||||||
|
|
|
|
||||||
help: The outer pattern can be modified to include the inner pattern.
|
help: the outer pattern can be modified to include the inner pattern
|
||||||
--> $DIR/collapsible_match2.rs:55:14
|
--> $DIR/collapsible_match2.rs:55:14
|
||||||
|
|
|
|
||||||
LL | Some(ref s) => match &*s {
|
LL | Some(ref s) => match &*s {
|
||||||
| ^^^^^ Replace this binding
|
| ^^^^^ replace this binding
|
||||||
LL | [n] => foo(n),
|
LL | [n] => foo(n),
|
||||||
| ^^^ with this pattern
|
| ^^^ with this pattern
|
||||||
|
|
||||||
|
|
21
tests/ui/crashes/ice-6179.rs
Normal file
21
tests/ui/crashes/ice-6179.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
//! This is a minimal reproducer for the ICE in https://github.com/rust-lang/rust-clippy/pull/6179.
|
||||||
|
//! The ICE is mainly caused by using `hir_ty_to_ty`. See the discussion in the PR for details.
|
||||||
|
|
||||||
|
#![warn(clippy::use_self)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
struct Foo {}
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
fn foo() -> Self {
|
||||||
|
impl Foo {
|
||||||
|
fn bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _: _ = 1;
|
||||||
|
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
135
tests/ui/default_numeric_fallback.rs
Normal file
135
tests/ui/default_numeric_fallback.rs
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
#![warn(clippy::default_numeric_fallback)]
|
||||||
|
#![allow(unused)]
|
||||||
|
#![allow(clippy::never_loop)]
|
||||||
|
#![allow(clippy::no_effect)]
|
||||||
|
#![allow(clippy::unnecessary_operation)]
|
||||||
|
|
||||||
|
mod basic_expr {
|
||||||
|
fn test() {
|
||||||
|
// Should lint unsuffixed literals typed `i32`.
|
||||||
|
let x = 22;
|
||||||
|
let x = [1, 2, 3];
|
||||||
|
let x = if true { (1, 2) } else { (3, 4) };
|
||||||
|
let x = match 1 {
|
||||||
|
1 => 1,
|
||||||
|
_ => 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Should lint unsuffixed literals typed `f64`.
|
||||||
|
let x = 0.12;
|
||||||
|
|
||||||
|
// Should NOT lint suffixed literals.
|
||||||
|
let x = 22_i32;
|
||||||
|
let x = 0.12_f64;
|
||||||
|
|
||||||
|
// Should NOT lint literals in init expr if `Local` has a type annotation.
|
||||||
|
let x: f64 = 0.1;
|
||||||
|
let x: [i32; 3] = [1, 2, 3];
|
||||||
|
let x: (i32, i32) = if true { (1, 2) } else { (3, 4) };
|
||||||
|
let x: _ = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod nested_local {
|
||||||
|
fn test() {
|
||||||
|
let x: _ = {
|
||||||
|
// Should lint this because this literal is not bound to any types.
|
||||||
|
let y = 1;
|
||||||
|
|
||||||
|
// Should NOT lint this because this literal is bound to `_` of outer `Local`.
|
||||||
|
1
|
||||||
|
};
|
||||||
|
|
||||||
|
let x: _ = if true {
|
||||||
|
// Should lint this because this literal is not bound to any types.
|
||||||
|
let y = 1;
|
||||||
|
|
||||||
|
// Should NOT lint this because this literal is bound to `_` of outer `Local`.
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
// Should lint this because this literal is not bound to any types.
|
||||||
|
let y = 1;
|
||||||
|
|
||||||
|
// Should NOT lint this because this literal is bound to `_` of outer `Local`.
|
||||||
|
2
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod function_def {
|
||||||
|
fn ret_i32() -> i32 {
|
||||||
|
// Even though the output type is specified,
|
||||||
|
// this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
// Should lint this because return type is inferred to `i32` and NOT bound to a concrete
|
||||||
|
// type.
|
||||||
|
let f = || -> _ { 1 };
|
||||||
|
|
||||||
|
// Even though the output type is specified,
|
||||||
|
// this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
|
||||||
|
let f = || -> i32 { 1 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod function_calls {
|
||||||
|
fn concrete_arg(x: i32) {}
|
||||||
|
|
||||||
|
fn generic_arg<T>(t: T) {}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
// Should NOT lint this because the argument type is bound to a concrete type.
|
||||||
|
concrete_arg(1);
|
||||||
|
|
||||||
|
// Should lint this because the argument type is inferred to `i32` and NOT bound to a concrete type.
|
||||||
|
generic_arg(1);
|
||||||
|
|
||||||
|
// Should lint this because the argument type is inferred to `i32` and NOT bound to a concrete type.
|
||||||
|
let x: _ = generic_arg(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod struct_ctor {
|
||||||
|
struct ConcreteStruct {
|
||||||
|
x: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GenericStruct<T> {
|
||||||
|
x: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
// Should NOT lint this because the field type is bound to a concrete type.
|
||||||
|
ConcreteStruct { x: 1 };
|
||||||
|
|
||||||
|
// Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type.
|
||||||
|
GenericStruct { x: 1 };
|
||||||
|
|
||||||
|
// Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type.
|
||||||
|
let _ = GenericStruct { x: 1 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod method_calls {
|
||||||
|
struct StructForMethodCallTest {}
|
||||||
|
|
||||||
|
impl StructForMethodCallTest {
|
||||||
|
fn concrete_arg(&self, x: i32) {}
|
||||||
|
|
||||||
|
fn generic_arg<T>(&self, t: T) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
let s = StructForMethodCallTest {};
|
||||||
|
|
||||||
|
// Should NOT lint this because the argument type is bound to a concrete type.
|
||||||
|
s.concrete_arg(1);
|
||||||
|
|
||||||
|
// Should lint this because the argument type is bound to a concrete type.
|
||||||
|
s.generic_arg(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
148
tests/ui/default_numeric_fallback.stderr
Normal file
148
tests/ui/default_numeric_fallback.stderr
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:10:17
|
||||||
|
|
|
||||||
|
LL | let x = 22;
|
||||||
|
| ^^ help: consider adding suffix: `22_i32`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::default-numeric-fallback` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:11:18
|
||||||
|
|
|
||||||
|
LL | let x = [1, 2, 3];
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:11:21
|
||||||
|
|
|
||||||
|
LL | let x = [1, 2, 3];
|
||||||
|
| ^ help: consider adding suffix: `2_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:11:24
|
||||||
|
|
|
||||||
|
LL | let x = [1, 2, 3];
|
||||||
|
| ^ help: consider adding suffix: `3_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:12:28
|
||||||
|
|
|
||||||
|
LL | let x = if true { (1, 2) } else { (3, 4) };
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:12:31
|
||||||
|
|
|
||||||
|
LL | let x = if true { (1, 2) } else { (3, 4) };
|
||||||
|
| ^ help: consider adding suffix: `2_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:12:44
|
||||||
|
|
|
||||||
|
LL | let x = if true { (1, 2) } else { (3, 4) };
|
||||||
|
| ^ help: consider adding suffix: `3_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:12:47
|
||||||
|
|
|
||||||
|
LL | let x = if true { (1, 2) } else { (3, 4) };
|
||||||
|
| ^ help: consider adding suffix: `4_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:13:23
|
||||||
|
|
|
||||||
|
LL | let x = match 1 {
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:14:13
|
||||||
|
|
|
||||||
|
LL | 1 => 1,
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:14:18
|
||||||
|
|
|
||||||
|
LL | 1 => 1,
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:15:18
|
||||||
|
|
|
||||||
|
LL | _ => 2,
|
||||||
|
| ^ help: consider adding suffix: `2_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:19:17
|
||||||
|
|
|
||||||
|
LL | let x = 0.12;
|
||||||
|
| ^^^^ help: consider adding suffix: `0.12_f64`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:37:21
|
||||||
|
|
|
||||||
|
LL | let y = 1;
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:45:21
|
||||||
|
|
|
||||||
|
LL | let y = 1;
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:51:21
|
||||||
|
|
|
||||||
|
LL | let y = 1;
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:63:9
|
||||||
|
|
|
||||||
|
LL | 1
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:69:27
|
||||||
|
|
|
||||||
|
LL | let f = || -> _ { 1 };
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:73:29
|
||||||
|
|
|
||||||
|
LL | let f = || -> i32 { 1 };
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:87:21
|
||||||
|
|
|
||||||
|
LL | generic_arg(1);
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:90:32
|
||||||
|
|
|
||||||
|
LL | let x: _ = generic_arg(1);
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:108:28
|
||||||
|
|
|
||||||
|
LL | GenericStruct { x: 1 };
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:111:36
|
||||||
|
|
|
||||||
|
LL | let _ = GenericStruct { x: 1 };
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: default numeric fallback might occur
|
||||||
|
--> $DIR/default_numeric_fallback.rs:131:23
|
||||||
|
|
|
||||||
|
LL | s.generic_arg(1);
|
||||||
|
| ^ help: consider adding suffix: `1_i32`
|
||||||
|
|
||||||
|
error: aborting due to 24 previous errors
|
||||||
|
|
|
@ -50,11 +50,23 @@ fn test_units() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This tests allowed identifiers.
|
/// This tests allowed identifiers.
|
||||||
|
/// KiB MiB GiB TiB PiB EiB
|
||||||
/// DirectX
|
/// DirectX
|
||||||
/// ECMAScript
|
/// ECMAScript
|
||||||
|
/// GPLv2 GPLv3
|
||||||
|
/// GitHub GitLab
|
||||||
|
/// IPv4 IPv6
|
||||||
|
/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
|
||||||
|
/// NaN NaNs
|
||||||
/// OAuth GraphQL
|
/// OAuth GraphQL
|
||||||
|
/// OCaml
|
||||||
|
/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
|
||||||
/// WebGL
|
/// WebGL
|
||||||
|
/// TensorFlow
|
||||||
|
/// TrueType
|
||||||
|
/// iOS macOS
|
||||||
/// TeX LaTeX BibTeX BibLaTeX
|
/// TeX LaTeX BibTeX BibLaTeX
|
||||||
|
/// MinGW
|
||||||
/// CamelCase (see also #2395)
|
/// CamelCase (see also #2395)
|
||||||
/// be_sure_we_got_to_the_end_of_it
|
/// be_sure_we_got_to_the_end_of_it
|
||||||
fn test_allowed() {
|
fn test_allowed() {
|
||||||
|
|
|
@ -55,133 +55,133 @@ LL | /// be_sure_we_got_to_the_end_of_it
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:59:5
|
--> $DIR/doc.rs:71:5
|
||||||
|
|
|
|
||||||
LL | /// be_sure_we_got_to_the_end_of_it
|
LL | /// be_sure_we_got_to_the_end_of_it
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put `link_with_underscores` between ticks in the documentation
|
error: you should put `link_with_underscores` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:63:22
|
--> $DIR/doc.rs:75:22
|
||||||
|
|
|
|
||||||
LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
|
LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put `inline_link2` between ticks in the documentation
|
error: you should put `inline_link2` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:66:21
|
--> $DIR/doc.rs:78:21
|
||||||
|
|
|
|
||||||
LL | /// It can also be [inline_link2].
|
LL | /// It can also be [inline_link2].
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:76:5
|
--> $DIR/doc.rs:88:5
|
||||||
|
|
|
|
||||||
LL | /// be_sure_we_got_to_the_end_of_it
|
LL | /// be_sure_we_got_to_the_end_of_it
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put `CamelCaseThing` between ticks in the documentation
|
error: you should put `CamelCaseThing` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:84:8
|
--> $DIR/doc.rs:96:8
|
||||||
|
|
|
|
||||||
LL | /// ## CamelCaseThing
|
LL | /// ## CamelCaseThing
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put `CamelCaseThing` between ticks in the documentation
|
error: you should put `CamelCaseThing` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:87:7
|
--> $DIR/doc.rs:99:7
|
||||||
|
|
|
|
||||||
LL | /// # CamelCaseThing
|
LL | /// # CamelCaseThing
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put `CamelCaseThing` between ticks in the documentation
|
error: you should put `CamelCaseThing` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:89:22
|
--> $DIR/doc.rs:101:22
|
||||||
|
|
|
|
||||||
LL | /// Not a title #897 CamelCaseThing
|
LL | /// Not a title #897 CamelCaseThing
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:90:5
|
--> $DIR/doc.rs:102:5
|
||||||
|
|
|
|
||||||
LL | /// be_sure_we_got_to_the_end_of_it
|
LL | /// be_sure_we_got_to_the_end_of_it
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:97:5
|
--> $DIR/doc.rs:109:5
|
||||||
|
|
|
|
||||||
LL | /// be_sure_we_got_to_the_end_of_it
|
LL | /// be_sure_we_got_to_the_end_of_it
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:110:5
|
--> $DIR/doc.rs:122:5
|
||||||
|
|
|
|
||||||
LL | /// be_sure_we_got_to_the_end_of_it
|
LL | /// be_sure_we_got_to_the_end_of_it
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put `FooBar` between ticks in the documentation
|
error: you should put `FooBar` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:121:43
|
--> $DIR/doc.rs:133:43
|
||||||
|
|
|
|
||||||
LL | /** E.g., serialization of an empty list: FooBar
|
LL | /** E.g., serialization of an empty list: FooBar
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: you should put `BarQuz` between ticks in the documentation
|
error: you should put `BarQuz` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:126:5
|
--> $DIR/doc.rs:138:5
|
||||||
|
|
|
|
||||||
LL | And BarQuz too.
|
LL | And BarQuz too.
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:127:1
|
--> $DIR/doc.rs:139:1
|
||||||
|
|
|
|
||||||
LL | be_sure_we_got_to_the_end_of_it
|
LL | be_sure_we_got_to_the_end_of_it
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put `FooBar` between ticks in the documentation
|
error: you should put `FooBar` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:132:43
|
--> $DIR/doc.rs:144:43
|
||||||
|
|
|
|
||||||
LL | /** E.g., serialization of an empty list: FooBar
|
LL | /** E.g., serialization of an empty list: FooBar
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: you should put `BarQuz` between ticks in the documentation
|
error: you should put `BarQuz` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:137:5
|
|
||||||
|
|
|
||||||
LL | And BarQuz too.
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
||||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
|
||||||
--> $DIR/doc.rs:138:1
|
|
||||||
|
|
|
||||||
LL | be_sure_we_got_to_the_end_of_it
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
|
||||||
--> $DIR/doc.rs:149:5
|
--> $DIR/doc.rs:149:5
|
||||||
|
|
|
|
||||||
|
LL | And BarQuz too.
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||||
|
--> $DIR/doc.rs:150:1
|
||||||
|
|
|
||||||
|
LL | be_sure_we_got_to_the_end_of_it
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||||
|
--> $DIR/doc.rs:161:5
|
||||||
|
|
|
||||||
LL | /// be_sure_we_got_to_the_end_of_it
|
LL | /// be_sure_we_got_to_the_end_of_it
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
|
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
|
||||||
--> $DIR/doc.rs:176:13
|
--> $DIR/doc.rs:188:13
|
||||||
|
|
|
|
||||||
LL | /// Not ok: http://www.unicode.org
|
LL | /// Not ok: http://www.unicode.org
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
|
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
|
||||||
--> $DIR/doc.rs:177:13
|
--> $DIR/doc.rs:189:13
|
||||||
|
|
|
|
||||||
LL | /// Not ok: https://www.unicode.org
|
LL | /// Not ok: https://www.unicode.org
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
|
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
|
||||||
--> $DIR/doc.rs:178:13
|
--> $DIR/doc.rs:190:13
|
||||||
|
|
|
|
||||||
LL | /// Not ok: http://www.unicode.org/
|
LL | /// Not ok: http://www.unicode.org/
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
|
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
|
||||||
--> $DIR/doc.rs:179:13
|
--> $DIR/doc.rs:191:13
|
||||||
|
|
|
|
||||||
LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
|
LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: you should put `mycrate::Collection` between ticks in the documentation
|
error: you should put `mycrate::Collection` between ticks in the documentation
|
||||||
--> $DIR/doc.rs:182:22
|
--> $DIR/doc.rs:194:22
|
||||||
|
|
|
|
||||||
LL | /// An iterator over mycrate::Collection's values.
|
LL | /// An iterator over mycrate::Collection's values.
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
@ -28,6 +28,15 @@ pub fn inner_body(opt: Option<u32>) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This needs to be documented
|
||||||
|
pub fn unreachable_and_panic() {
|
||||||
|
if true {
|
||||||
|
unreachable!()
|
||||||
|
} else {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This is documented
|
/// This is documented
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
|
@ -69,6 +78,19 @@ pub fn todo_documented() {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This is documented
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// We still need to do this part
|
||||||
|
pub fn unreachable_amd_panic_documented() {
|
||||||
|
if true {
|
||||||
|
unreachable!()
|
||||||
|
} else {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This is okay because it is private
|
/// This is okay because it is private
|
||||||
fn unwrap_private() {
|
fn unwrap_private() {
|
||||||
let result = Err("Hi");
|
let result = Err("Hi");
|
||||||
|
@ -93,3 +115,8 @@ fn inner_body_private(opt: Option<u32>) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This is okay because unreachable
|
||||||
|
pub fn unreachable() {
|
||||||
|
unreachable!("This function panics")
|
||||||
|
}
|
||||||
|
|
|
@ -63,5 +63,24 @@ LL | panic!()
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: docs for function which may panic missing `# Panics` section
|
||||||
|
--> $DIR/doc_panics.rs:32:1
|
||||||
|
|
|
||||||
|
LL | / pub fn unreachable_and_panic() {
|
||||||
|
LL | | if true {
|
||||||
|
LL | | unreachable!()
|
||||||
|
LL | | } else {
|
||||||
|
LL | | panic!()
|
||||||
|
LL | | }
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
note: first possible panic found here
|
||||||
|
--> $DIR/doc_panics.rs:36:9
|
||||||
|
|
|
||||||
|
LL | panic!()
|
||||||
|
| ^^^^^^^^
|
||||||
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
|
|
@ -133,4 +133,17 @@ pub enum NetworkLayer {
|
||||||
Layer3,
|
Layer3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// should lint suggesting `IData`, not only `Data` (see #4639)
|
||||||
|
enum IDataRequest {
|
||||||
|
PutIData(String),
|
||||||
|
GetIData(String),
|
||||||
|
DeleteUnpubIData(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
enum HIDataRequest {
|
||||||
|
PutHIData(String),
|
||||||
|
GetHIData(String),
|
||||||
|
DeleteUnpubHIData(String),
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -97,5 +97,29 @@ LL | | }
|
||||||
= note: `-D clippy::pub-enum-variant-names` implied by `-D warnings`
|
= note: `-D clippy::pub-enum-variant-names` implied by `-D warnings`
|
||||||
= help: remove the prefixes and use full paths to the variants instead of glob imports
|
= help: remove the prefixes and use full paths to the variants instead of glob imports
|
||||||
|
|
||||||
error: aborting due to 10 previous errors
|
error: all variants have the same postfix: `IData`
|
||||||
|
--> $DIR/enum_variants.rs:137:1
|
||||||
|
|
|
||||||
|
LL | / enum IDataRequest {
|
||||||
|
LL | | PutIData(String),
|
||||||
|
LL | | GetIData(String),
|
||||||
|
LL | | DeleteUnpubIData(String),
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
= help: remove the postfixes and use full paths to the variants instead of glob imports
|
||||||
|
|
||||||
|
error: all variants have the same postfix: `HIData`
|
||||||
|
--> $DIR/enum_variants.rs:143:1
|
||||||
|
|
|
||||||
|
LL | / enum HIDataRequest {
|
||||||
|
LL | | PutHIData(String),
|
||||||
|
LL | | GetHIData(String),
|
||||||
|
LL | | DeleteUnpubHIData(String),
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
= help: remove the postfixes and use full paths to the variants instead of glob imports
|
||||||
|
|
||||||
|
error: aborting due to 12 previous errors
|
||||||
|
|
||||||
|
|
52
tests/ui/from_str_radix_10.rs
Normal file
52
tests/ui/from_str_radix_10.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#![warn(clippy::from_str_radix_10)]
|
||||||
|
|
||||||
|
mod some_mod {
|
||||||
|
// fake function that shouldn't trigger the lint
|
||||||
|
pub fn from_str_radix(_: &str, _: u32) -> Result<(), std::num::ParseIntError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fake function that shouldn't trigger the lint
|
||||||
|
fn from_str_radix(_: &str, _: u32) -> Result<(), std::num::ParseIntError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
// to test parenthesis addition
|
||||||
|
struct Test;
|
||||||
|
|
||||||
|
impl std::ops::Add<Test> for Test {
|
||||||
|
type Output = &'static str;
|
||||||
|
|
||||||
|
fn add(self, _: Self) -> Self::Output {
|
||||||
|
"304"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// all of these should trigger the lint
|
||||||
|
u32::from_str_radix("30", 10)?;
|
||||||
|
i64::from_str_radix("24", 10)?;
|
||||||
|
isize::from_str_radix("100", 10)?;
|
||||||
|
u8::from_str_radix("7", 10)?;
|
||||||
|
u16::from_str_radix(&("10".to_owned() + "5"), 10)?;
|
||||||
|
i128::from_str_radix(Test + Test, 10)?;
|
||||||
|
|
||||||
|
let string = "300";
|
||||||
|
i32::from_str_radix(string, 10)?;
|
||||||
|
|
||||||
|
let stringier = "400".to_string();
|
||||||
|
i32::from_str_radix(&stringier, 10)?;
|
||||||
|
|
||||||
|
// none of these should trigger the lint
|
||||||
|
u16::from_str_radix("20", 3)?;
|
||||||
|
i32::from_str_radix("45", 12)?;
|
||||||
|
usize::from_str_radix("10", 16)?;
|
||||||
|
i128::from_str_radix("10", 13)?;
|
||||||
|
some_mod::from_str_radix("50", 10)?;
|
||||||
|
some_mod::from_str_radix("50", 6)?;
|
||||||
|
from_str_radix("50", 10)?;
|
||||||
|
from_str_radix("50", 6)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
52
tests/ui/from_str_radix_10.stderr
Normal file
52
tests/ui/from_str_radix_10.stderr
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
|
--> $DIR/from_str_radix_10.rs:28:5
|
||||||
|
|
|
||||||
|
LL | u32::from_str_radix("30", 10)?;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"30".parse::<u32>()`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::from-str-radix-10` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
|
--> $DIR/from_str_radix_10.rs:29:5
|
||||||
|
|
|
||||||
|
LL | i64::from_str_radix("24", 10)?;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"24".parse::<i64>()`
|
||||||
|
|
||||||
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
|
--> $DIR/from_str_radix_10.rs:30:5
|
||||||
|
|
|
||||||
|
LL | isize::from_str_radix("100", 10)?;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"100".parse::<isize>()`
|
||||||
|
|
||||||
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
|
--> $DIR/from_str_radix_10.rs:31:5
|
||||||
|
|
|
||||||
|
LL | u8::from_str_radix("7", 10)?;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"7".parse::<u8>()`
|
||||||
|
|
||||||
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
|
--> $DIR/from_str_radix_10.rs:32:5
|
||||||
|
|
|
||||||
|
LL | u16::from_str_radix(&("10".to_owned() + "5"), 10)?;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(("10".to_owned() + "5")).parse::<u16>()`
|
||||||
|
|
||||||
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
|
--> $DIR/from_str_radix_10.rs:33:5
|
||||||
|
|
|
||||||
|
LL | i128::from_str_radix(Test + Test, 10)?;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(Test + Test).parse::<i128>()`
|
||||||
|
|
||||||
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
|
--> $DIR/from_str_radix_10.rs:36:5
|
||||||
|
|
|
||||||
|
LL | i32::from_str_radix(string, 10)?;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.parse::<i32>()`
|
||||||
|
|
||||||
|
error: this call to `from_str_radix` can be replaced with a call to `str::parse`
|
||||||
|
--> $DIR/from_str_radix_10.rs:39:5
|
||||||
|
|
|
||||||
|
LL | i32::from_str_radix(&stringier, 10)?;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `stringier.parse::<i32>()`
|
||||||
|
|
||||||
|
error: aborting due to 8 previous errors
|
||||||
|
|
|
@ -12,7 +12,7 @@ fn if_same_then_else2() -> Result<&'static str, ()> {
|
||||||
if true {
|
if true {
|
||||||
for _ in &[42] {
|
for _ in &[42] {
|
||||||
let foo: &Option<_> = &Some::<u8>(42);
|
let foo: &Option<_> = &Some::<u8>(42);
|
||||||
if true {
|
if foo.is_some() {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
|
@ -21,8 +21,8 @@ fn if_same_then_else2() -> Result<&'static str, ()> {
|
||||||
} else {
|
} else {
|
||||||
//~ ERROR same body as `if` block
|
//~ ERROR same body as `if` block
|
||||||
for _ in &[42] {
|
for _ in &[42] {
|
||||||
let foo: &Option<_> = &Some::<u8>(42);
|
let bar: &Option<_> = &Some::<u8>(42);
|
||||||
if true {
|
if bar.is_some() {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -5,7 +5,7 @@ LL | } else {
|
||||||
| ____________^
|
| ____________^
|
||||||
LL | | //~ ERROR same body as `if` block
|
LL | | //~ ERROR same body as `if` block
|
||||||
LL | | for _ in &[42] {
|
LL | | for _ in &[42] {
|
||||||
LL | | let foo: &Option<_> = &Some::<u8>(42);
|
LL | | let bar: &Option<_> = &Some::<u8>(42);
|
||||||
... |
|
... |
|
||||||
LL | | }
|
LL | | }
|
||||||
LL | | }
|
LL | | }
|
||||||
|
@ -19,7 +19,7 @@ LL | if true {
|
||||||
| _____________^
|
| _____________^
|
||||||
LL | | for _ in &[42] {
|
LL | | for _ in &[42] {
|
||||||
LL | | let foo: &Option<_> = &Some::<u8>(42);
|
LL | | let foo: &Option<_> = &Some::<u8>(42);
|
||||||
LL | | if true {
|
LL | | if foo.is_some() {
|
||||||
... |
|
... |
|
||||||
LL | | }
|
LL | | }
|
||||||
LL | | } else {
|
LL | | } else {
|
||||||
|
|
61
tests/ui/inconsistent_struct_constructor.fixed
Normal file
61
tests/ui/inconsistent_struct_constructor.fixed
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
// run-rustfix
|
||||||
|
// edition:2018
|
||||||
|
#![warn(clippy::inconsistent_struct_constructor)]
|
||||||
|
#![allow(clippy::redundant_field_names)]
|
||||||
|
#![allow(clippy::unnecessary_operation)]
|
||||||
|
#![allow(clippy::no_effect)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Foo {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
z: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
mod without_base {
|
||||||
|
use super::Foo;
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
let x = 1;
|
||||||
|
let y = 1;
|
||||||
|
let z = 1;
|
||||||
|
|
||||||
|
// Should lint.
|
||||||
|
Foo { x, y, z };
|
||||||
|
|
||||||
|
// Shoule NOT lint because the order is the same as in the definition.
|
||||||
|
Foo { x, y, z };
|
||||||
|
|
||||||
|
// Should NOT lint because z is not a shorthand init.
|
||||||
|
Foo { y, x, z: z };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod with_base {
|
||||||
|
use super::Foo;
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
let x = 1;
|
||||||
|
let z = 1;
|
||||||
|
|
||||||
|
// Should lint.
|
||||||
|
Foo { x, z, ..Default::default() };
|
||||||
|
|
||||||
|
// Should NOT lint because the order is consistent with the definition.
|
||||||
|
Foo {
|
||||||
|
x,
|
||||||
|
z,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Should NOT lint because z is not a shorthand init.
|
||||||
|
Foo {
|
||||||
|
z: z,
|
||||||
|
x,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
65
tests/ui/inconsistent_struct_constructor.rs
Normal file
65
tests/ui/inconsistent_struct_constructor.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
// run-rustfix
|
||||||
|
// edition:2018
|
||||||
|
#![warn(clippy::inconsistent_struct_constructor)]
|
||||||
|
#![allow(clippy::redundant_field_names)]
|
||||||
|
#![allow(clippy::unnecessary_operation)]
|
||||||
|
#![allow(clippy::no_effect)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Foo {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
z: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
mod without_base {
|
||||||
|
use super::Foo;
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
let x = 1;
|
||||||
|
let y = 1;
|
||||||
|
let z = 1;
|
||||||
|
|
||||||
|
// Should lint.
|
||||||
|
Foo { y, x, z };
|
||||||
|
|
||||||
|
// Shoule NOT lint because the order is the same as in the definition.
|
||||||
|
Foo { x, y, z };
|
||||||
|
|
||||||
|
// Should NOT lint because z is not a shorthand init.
|
||||||
|
Foo { y, x, z: z };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod with_base {
|
||||||
|
use super::Foo;
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
let x = 1;
|
||||||
|
let z = 1;
|
||||||
|
|
||||||
|
// Should lint.
|
||||||
|
Foo {
|
||||||
|
z,
|
||||||
|
x,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Should NOT lint because the order is consistent with the definition.
|
||||||
|
Foo {
|
||||||
|
x,
|
||||||
|
z,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Should NOT lint because z is not a shorthand init.
|
||||||
|
Foo {
|
||||||
|
z: z,
|
||||||
|
x,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
20
tests/ui/inconsistent_struct_constructor.stderr
Normal file
20
tests/ui/inconsistent_struct_constructor.stderr
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
error: inconsistent struct constructor
|
||||||
|
--> $DIR/inconsistent_struct_constructor.rs:25:9
|
||||||
|
|
|
||||||
|
LL | Foo { y, x, z };
|
||||||
|
| ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: inconsistent struct constructor
|
||||||
|
--> $DIR/inconsistent_struct_constructor.rs:43:9
|
||||||
|
|
|
||||||
|
LL | / Foo {
|
||||||
|
LL | | z,
|
||||||
|
LL | | x,
|
||||||
|
LL | | ..Default::default()
|
||||||
|
LL | | };
|
||||||
|
| |_________^ help: try: `Foo { x, z, ..Default::default() }`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -14,6 +14,7 @@ struct C;
|
||||||
struct D;
|
struct D;
|
||||||
struct E;
|
struct E;
|
||||||
struct F;
|
struct F;
|
||||||
|
struct G;
|
||||||
|
|
||||||
impl A {
|
impl A {
|
||||||
// Should be detected; emit warning
|
// Should be detected; emit warning
|
||||||
|
@ -73,6 +74,13 @@ impl F {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl G {
|
||||||
|
// Should not be detected, as it does not match the function signature
|
||||||
|
fn to_string<const _N: usize>(&self) -> String {
|
||||||
|
"G.to_string()".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let a = A;
|
let a = A;
|
||||||
a.to_string();
|
a.to_string();
|
||||||
|
@ -93,4 +101,7 @@ fn main() {
|
||||||
|
|
||||||
let f = F;
|
let f = F;
|
||||||
f.to_string(1);
|
f.to_string(1);
|
||||||
|
|
||||||
|
let g = G;
|
||||||
|
g.to_string::<1>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: implementation of inherent method `to_string(&self) -> String` for type `A`
|
error: implementation of inherent method `to_string(&self) -> String` for type `A`
|
||||||
--> $DIR/inherent_to_string.rs:20:5
|
--> $DIR/inherent_to_string.rs:21:5
|
||||||
|
|
|
|
||||||
LL | / fn to_string(&self) -> String {
|
LL | / fn to_string(&self) -> String {
|
||||||
LL | | "A.to_string()".to_string()
|
LL | | "A.to_string()".to_string()
|
||||||
|
@ -10,7 +10,7 @@ LL | | }
|
||||||
= help: implement trait `Display` for type `A` instead
|
= help: implement trait `Display` for type `A` instead
|
||||||
|
|
||||||
error: type `C` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`
|
error: type `C` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`
|
||||||
--> $DIR/inherent_to_string.rs:44:5
|
--> $DIR/inherent_to_string.rs:45:5
|
||||||
|
|
|
|
||||||
LL | / fn to_string(&self) -> String {
|
LL | / fn to_string(&self) -> String {
|
||||||
LL | | "C.to_string()".to_string()
|
LL | | "C.to_string()".to_string()
|
||||||
|
|
70
tests/ui/manual_map_option.fixed
Normal file
70
tests/ui/manual_map_option.fixed
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![warn(clippy::manual_map)]
|
||||||
|
#![allow(clippy::no_effect, clippy::map_identity, clippy::unit_arg, clippy::match_ref_pats)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Some(0).map(|_| 2);
|
||||||
|
|
||||||
|
Some(0).map(|x| x + 1);
|
||||||
|
|
||||||
|
Some("").map(|x| x.is_empty());
|
||||||
|
|
||||||
|
Some(0).map(|x| !x);
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
Some(0).map(std::convert::identity);
|
||||||
|
|
||||||
|
Some(&String::new()).map(|x| str::len(x));
|
||||||
|
|
||||||
|
match Some(0) {
|
||||||
|
Some(x) if false => Some(x + 1),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some([0, 1]).as_ref().map(|x| x[0]);
|
||||||
|
|
||||||
|
Some(0).map(|x| x * 2);
|
||||||
|
|
||||||
|
Some(String::new()).as_ref().map(|x| x.is_empty());
|
||||||
|
|
||||||
|
Some(String::new()).as_ref().map(|x| x.len());
|
||||||
|
|
||||||
|
Some(0).map(|x| x + x);
|
||||||
|
|
||||||
|
#[warn(clippy::option_map_unit_fn)]
|
||||||
|
match &mut Some(String::new()) {
|
||||||
|
Some(x) => Some(x.push_str("")),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(clippy::option_map_unit_fn)]
|
||||||
|
{
|
||||||
|
Some(String::new()).as_mut().map(|x| x.push_str(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(String::new()).as_ref().map(|x| x.len());
|
||||||
|
|
||||||
|
Some(String::new()).as_ref().map(|x| x.is_empty());
|
||||||
|
|
||||||
|
Some((0, 1, 2)).map(|(x, y, z)| x + y + z);
|
||||||
|
|
||||||
|
Some([1, 2, 3]).map(|[first, ..]| first);
|
||||||
|
|
||||||
|
Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x));
|
||||||
|
|
||||||
|
match Some((String::new(), 0)) {
|
||||||
|
Some((ref x, y)) => Some((y, x)),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match Some(Some(0)) {
|
||||||
|
Some(Some(_)) | Some(None) => Some(0),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match Some(Some((0, 1))) {
|
||||||
|
Some(Some((x, 1))) => Some(x),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
}
|
122
tests/ui/manual_map_option.rs
Normal file
122
tests/ui/manual_map_option.rs
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
// run-rustfix
|
||||||
|
|
||||||
|
#![warn(clippy::manual_map)]
|
||||||
|
#![allow(clippy::no_effect, clippy::map_identity, clippy::unit_arg, clippy::match_ref_pats)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match Some(0) {
|
||||||
|
Some(_) => Some(2),
|
||||||
|
None::<u32> => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match Some(0) {
|
||||||
|
Some(x) => Some(x + 1),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match Some("") {
|
||||||
|
Some(x) => Some(x.is_empty()),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(x) = Some(0) {
|
||||||
|
Some(!x)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
match Some(0) {
|
||||||
|
Some(x) => { Some(std::convert::identity(x)) }
|
||||||
|
None => { None }
|
||||||
|
};
|
||||||
|
|
||||||
|
match Some(&String::new()) {
|
||||||
|
Some(x) => Some(str::len(x)),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match Some(0) {
|
||||||
|
Some(x) if false => Some(x + 1),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match &Some([0, 1]) {
|
||||||
|
Some(x) => Some(x[0]),
|
||||||
|
&None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match &Some(0) {
|
||||||
|
&Some(x) => Some(x * 2),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match Some(String::new()) {
|
||||||
|
Some(ref x) => Some(x.is_empty()),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match &&Some(String::new()) {
|
||||||
|
Some(x) => Some(x.len()),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match &&Some(0) {
|
||||||
|
&&Some(x) => Some(x + x),
|
||||||
|
&&_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[warn(clippy::option_map_unit_fn)]
|
||||||
|
match &mut Some(String::new()) {
|
||||||
|
Some(x) => Some(x.push_str("")),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(clippy::option_map_unit_fn)]
|
||||||
|
{
|
||||||
|
match &mut Some(String::new()) {
|
||||||
|
Some(x) => Some(x.push_str("")),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
match &mut Some(String::new()) {
|
||||||
|
Some(ref x) => Some(x.len()),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match &mut &Some(String::new()) {
|
||||||
|
Some(x) => Some(x.is_empty()),
|
||||||
|
&mut _ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match Some((0, 1, 2)) {
|
||||||
|
Some((x, y, z)) => Some(x + y + z),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match Some([1, 2, 3]) {
|
||||||
|
Some([first, ..]) => Some(first),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match &Some((String::new(), "test")) {
|
||||||
|
Some((x, y)) => Some((y, x)),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match Some((String::new(), 0)) {
|
||||||
|
Some((ref x, y)) => Some((y, x)),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match Some(Some(0)) {
|
||||||
|
Some(Some(_)) | Some(None) => Some(0),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match Some(Some((0, 1))) {
|
||||||
|
Some(Some((x, 1))) => Some(x),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
}
|
158
tests/ui/manual_map_option.stderr
Normal file
158
tests/ui/manual_map_option.stderr
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:7:5
|
||||||
|
|
|
||||||
|
LL | / match Some(0) {
|
||||||
|
LL | | Some(_) => Some(2),
|
||||||
|
LL | | None::<u32> => None,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some(0).map(|_| 2)`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::manual-map` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:12:5
|
||||||
|
|
|
||||||
|
LL | / match Some(0) {
|
||||||
|
LL | | Some(x) => Some(x + 1),
|
||||||
|
LL | | _ => None,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some(0).map(|x| x + 1)`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:17:5
|
||||||
|
|
|
||||||
|
LL | / match Some("") {
|
||||||
|
LL | | Some(x) => Some(x.is_empty()),
|
||||||
|
LL | | None => None,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some("").map(|x| x.is_empty())`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:22:5
|
||||||
|
|
|
||||||
|
LL | / if let Some(x) = Some(0) {
|
||||||
|
LL | | Some(!x)
|
||||||
|
LL | | } else {
|
||||||
|
LL | | None
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some(0).map(|x| !x)`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:29:5
|
||||||
|
|
|
||||||
|
LL | / match Some(0) {
|
||||||
|
LL | | Some(x) => { Some(std::convert::identity(x)) }
|
||||||
|
LL | | None => { None }
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some(0).map(std::convert::identity)`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:34:5
|
||||||
|
|
|
||||||
|
LL | / match Some(&String::new()) {
|
||||||
|
LL | | Some(x) => Some(str::len(x)),
|
||||||
|
LL | | None => None,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some(&String::new()).map(|x| str::len(x))`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:44:5
|
||||||
|
|
|
||||||
|
LL | / match &Some([0, 1]) {
|
||||||
|
LL | | Some(x) => Some(x[0]),
|
||||||
|
LL | | &None => None,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some([0, 1]).as_ref().map(|x| x[0])`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:49:5
|
||||||
|
|
|
||||||
|
LL | / match &Some(0) {
|
||||||
|
LL | | &Some(x) => Some(x * 2),
|
||||||
|
LL | | None => None,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some(0).map(|x| x * 2)`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:54:5
|
||||||
|
|
|
||||||
|
LL | / match Some(String::new()) {
|
||||||
|
LL | | Some(ref x) => Some(x.is_empty()),
|
||||||
|
LL | | _ => None,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:59:5
|
||||||
|
|
|
||||||
|
LL | / match &&Some(String::new()) {
|
||||||
|
LL | | Some(x) => Some(x.len()),
|
||||||
|
LL | | _ => None,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:64:5
|
||||||
|
|
|
||||||
|
LL | / match &&Some(0) {
|
||||||
|
LL | | &&Some(x) => Some(x + x),
|
||||||
|
LL | | &&_ => None,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some(0).map(|x| x + x)`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:77:9
|
||||||
|
|
|
||||||
|
LL | / match &mut Some(String::new()) {
|
||||||
|
LL | | Some(x) => Some(x.push_str("")),
|
||||||
|
LL | | None => None,
|
||||||
|
LL | | };
|
||||||
|
| |_________^ help: try this: `Some(String::new()).as_mut().map(|x| x.push_str(""))`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:83:5
|
||||||
|
|
|
||||||
|
LL | / match &mut Some(String::new()) {
|
||||||
|
LL | | Some(ref x) => Some(x.len()),
|
||||||
|
LL | | None => None,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:88:5
|
||||||
|
|
|
||||||
|
LL | / match &mut &Some(String::new()) {
|
||||||
|
LL | | Some(x) => Some(x.is_empty()),
|
||||||
|
LL | | &mut _ => None,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:93:5
|
||||||
|
|
|
||||||
|
LL | / match Some((0, 1, 2)) {
|
||||||
|
LL | | Some((x, y, z)) => Some(x + y + z),
|
||||||
|
LL | | None => None,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some((0, 1, 2)).map(|(x, y, z)| x + y + z)`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:98:5
|
||||||
|
|
|
||||||
|
LL | / match Some([1, 2, 3]) {
|
||||||
|
LL | | Some([first, ..]) => Some(first),
|
||||||
|
LL | | None => None,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some([1, 2, 3]).map(|[first, ..]| first)`
|
||||||
|
|
||||||
|
error: manual implementation of `Option::map`
|
||||||
|
--> $DIR/manual_map_option.rs:103:5
|
||||||
|
|
|
||||||
|
LL | / match &Some((String::new(), "test")) {
|
||||||
|
LL | | Some((x, y)) => Some((y, x)),
|
||||||
|
LL | | None => None,
|
||||||
|
LL | | };
|
||||||
|
| |_____^ help: try this: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))`
|
||||||
|
|
||||||
|
error: aborting due to 17 previous errors
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
#![allow(clippy::unnecessary_wraps)]
|
#![warn(clippy::result_unit_err)]
|
||||||
#[warn(clippy::result_unit_err)]
|
|
||||||
#[allow(unused)]
|
|
||||||
|
|
||||||
pub fn returns_unit_error() -> Result<u32, ()> {
|
pub fn returns_unit_error() -> Result<u32, ()> {
|
||||||
Err(())
|
Err(())
|
||||||
|
@ -36,4 +34,23 @@ impl UnitErrorHolder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/rust-lang/rust-clippy/issues/6546
|
||||||
|
pub mod issue_6546 {
|
||||||
|
type ResInv<A, B> = Result<B, A>;
|
||||||
|
|
||||||
|
pub fn should_lint() -> ResInv<(), usize> {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn should_not_lint() -> ResInv<usize, ()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
type MyRes<A, B> = Result<(A, B), Box<dyn std::error::Error>>;
|
||||||
|
|
||||||
|
pub fn should_not_lint2(x: i32) -> MyRes<i32, ()> {
|
||||||
|
Ok((x, ()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: this returns a `Result<_, ()>
|
error: this returns a `Result<_, ()>
|
||||||
--> $DIR/result_unit_error.rs:5:1
|
--> $DIR/result_unit_error.rs:3:1
|
||||||
|
|
|
|
||||||
LL | pub fn returns_unit_error() -> Result<u32, ()> {
|
LL | pub fn returns_unit_error() -> Result<u32, ()> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -8,7 +8,7 @@ LL | pub fn returns_unit_error() -> Result<u32, ()> {
|
||||||
= help: use a custom Error type instead
|
= help: use a custom Error type instead
|
||||||
|
|
||||||
error: this returns a `Result<_, ()>
|
error: this returns a `Result<_, ()>
|
||||||
--> $DIR/result_unit_error.rs:14:5
|
--> $DIR/result_unit_error.rs:12:5
|
||||||
|
|
|
|
||||||
LL | fn get_that_error(&self) -> Result<bool, ()>;
|
LL | fn get_that_error(&self) -> Result<bool, ()>;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -16,7 +16,7 @@ LL | fn get_that_error(&self) -> Result<bool, ()>;
|
||||||
= help: use a custom Error type instead
|
= help: use a custom Error type instead
|
||||||
|
|
||||||
error: this returns a `Result<_, ()>
|
error: this returns a `Result<_, ()>
|
||||||
--> $DIR/result_unit_error.rs:16:5
|
--> $DIR/result_unit_error.rs:14:5
|
||||||
|
|
|
|
||||||
LL | fn get_this_one_too(&self) -> Result<bool, ()> {
|
LL | fn get_this_one_too(&self) -> Result<bool, ()> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -24,12 +24,20 @@ LL | fn get_this_one_too(&self) -> Result<bool, ()> {
|
||||||
= help: use a custom Error type instead
|
= help: use a custom Error type instead
|
||||||
|
|
||||||
error: this returns a `Result<_, ()>
|
error: this returns a `Result<_, ()>
|
||||||
--> $DIR/result_unit_error.rs:34:5
|
--> $DIR/result_unit_error.rs:32:5
|
||||||
|
|
|
|
||||||
LL | pub fn unit_error(&self) -> Result<usize, ()> {
|
LL | pub fn unit_error(&self) -> Result<usize, ()> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: use a custom Error type instead
|
= help: use a custom Error type instead
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: this returns a `Result<_, ()>
|
||||||
|
--> $DIR/result_unit_error.rs:41:5
|
||||||
|
|
|
||||||
|
LL | pub fn should_lint() -> ResInv<(), usize> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: use a custom Error type instead
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#![warn(clippy::temporary_assignment)]
|
#![warn(clippy::temporary_assignment)]
|
||||||
#![allow(const_item_mutation)]
|
|
||||||
|
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: assignment to temporary
|
error: assignment to temporary
|
||||||
--> $DIR/temporary_assignment.rs:48:5
|
--> $DIR/temporary_assignment.rs:47:5
|
||||||
|
|
|
|
||||||
LL | Struct { field: 0 }.field = 1;
|
LL | Struct { field: 0 }.field = 1;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -7,7 +7,7 @@ LL | Struct { field: 0 }.field = 1;
|
||||||
= note: `-D clippy::temporary-assignment` implied by `-D warnings`
|
= note: `-D clippy::temporary-assignment` implied by `-D warnings`
|
||||||
|
|
||||||
error: assignment to temporary
|
error: assignment to temporary
|
||||||
--> $DIR/temporary_assignment.rs:49:5
|
--> $DIR/temporary_assignment.rs:48:5
|
||||||
|
|
|
|
||||||
LL | / MultiStruct {
|
LL | / MultiStruct {
|
||||||
LL | | structure: Struct { field: 0 },
|
LL | | structure: Struct { field: 0 },
|
||||||
|
@ -17,13 +17,13 @@ LL | | .field = 1;
|
||||||
| |______________^
|
| |______________^
|
||||||
|
|
||||||
error: assignment to temporary
|
error: assignment to temporary
|
||||||
--> $DIR/temporary_assignment.rs:54:5
|
--> $DIR/temporary_assignment.rs:53:5
|
||||||
|
|
|
|
||||||
LL | ArrayStruct { array: [0] }.array[0] = 1;
|
LL | ArrayStruct { array: [0] }.array[0] = 1;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: assignment to temporary
|
error: assignment to temporary
|
||||||
--> $DIR/temporary_assignment.rs:55:5
|
--> $DIR/temporary_assignment.rs:54:5
|
||||||
|
|
|
|
||||||
LL | (0, 0).0 = 1;
|
LL | (0, 0).0 = 1;
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue