mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 09:14:20 +00:00
Merge remote-tracking branch 'upstream/master' into rustup
This commit is contained in:
commit
d02016d686
5
.github/ISSUE_TEMPLATE/new_lint.md
vendored
5
.github/ISSUE_TEMPLATE/new_lint.md
vendored
@ -15,8 +15,9 @@ labels: A-lint
|
||||
*What is the advantage of the recommended code over the original code*
|
||||
|
||||
For example:
|
||||
- Remove bounce checking inserted by ...
|
||||
- Remove the need to duplicating/storing/typo ...
|
||||
- Remove bounds check inserted by ...
|
||||
- Remove the need to duplicate/store ...
|
||||
- Remove typo ...
|
||||
|
||||
### Drawbacks
|
||||
|
||||
|
6
.github/workflows/clippy.yml
vendored
6
.github/workflows/clippy.yml
vendored
@ -49,13 +49,13 @@ jobs:
|
||||
echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build
|
||||
run: cargo build --features deny-warnings,internal-lints
|
||||
run: cargo build --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
|
||||
- name: Test
|
||||
run: cargo test --features deny-warnings,internal-lints
|
||||
run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
|
||||
- name: Test clippy_lints
|
||||
run: cargo test --features deny-warnings,internal-lints
|
||||
run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
working-directory: clippy_lints
|
||||
|
||||
- name: Test rustc_tools_util
|
||||
|
6
.github/workflows/clippy_bors.yml
vendored
6
.github/workflows/clippy_bors.yml
vendored
@ -112,13 +112,13 @@ jobs:
|
||||
echo "$SYSROOT/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Build
|
||||
run: cargo build --features deny-warnings,internal-lints
|
||||
run: cargo build --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
|
||||
- name: Test
|
||||
run: cargo test --features deny-warnings,internal-lints
|
||||
run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
|
||||
- name: Test clippy_lints
|
||||
run: cargo test --features deny-warnings,internal-lints
|
||||
run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
|
||||
working-directory: clippy_lints
|
||||
|
||||
- name: Test rustc_tools_util
|
||||
|
2
.github/workflows/remark.yml
vendored
2
.github/workflows/remark.yml
vendored
@ -20,6 +20,8 @@ jobs:
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v1.4.4
|
||||
with:
|
||||
node-version: '12.x'
|
||||
|
||||
- name: Install remark
|
||||
run: npm install remark-cli remark-lint remark-lint-maximum-line-length remark-preset-lint-recommended remark-gfm
|
||||
|
141
CHANGELOG.md
141
CHANGELOG.md
@ -6,11 +6,141 @@ document.
|
||||
|
||||
## Unreleased / In Rust Nightly
|
||||
|
||||
[3ae8faf...master](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...master)
|
||||
[74d1561...master](https://github.com/rust-lang/rust-clippy/compare/74d1561...master)
|
||||
|
||||
## Rust 1.55
|
||||
|
||||
Current beta, release 2021-09-09
|
||||
|
||||
[3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561)
|
||||
|
||||
### Important Changes
|
||||
|
||||
* Stabilized `cargo clippy --fix` :tada:
|
||||
[#7405](https://github.com/rust-lang/rust-clippy/pull/7405)
|
||||
|
||||
### New Lints
|
||||
|
||||
* [`rc_mutex`]
|
||||
[#7316](https://github.com/rust-lang/rust-clippy/pull/7316)
|
||||
* [`nonstandard_macro_braces`]
|
||||
[#7299](https://github.com/rust-lang/rust-clippy/pull/7299)
|
||||
* [`strlen_on_c_strings`]
|
||||
[#7243](https://github.com/rust-lang/rust-clippy/pull/7243)
|
||||
* [`self_named_constructors`]
|
||||
[#7403](https://github.com/rust-lang/rust-clippy/pull/7403)
|
||||
* [`disallowed_script_idents`]
|
||||
[#7400](https://github.com/rust-lang/rust-clippy/pull/7400)
|
||||
* [`disallowed_type`]
|
||||
[#7315](https://github.com/rust-lang/rust-clippy/pull/7315)
|
||||
* [`missing_enforced_import_renames`]
|
||||
[#7300](https://github.com/rust-lang/rust-clippy/pull/7300)
|
||||
* [`extend_with_drain`]
|
||||
[#7270](https://github.com/rust-lang/rust-clippy/pull/7270)
|
||||
|
||||
### Moves and Deprecations
|
||||
|
||||
* Moved [`from_iter_instead_of_collect`] to `pedantic`
|
||||
[#7375](https://github.com/rust-lang/rust-clippy/pull/7375)
|
||||
* Added `suspicious` as a new lint group for *code that is most likely wrong or useless*
|
||||
[#7350](https://github.com/rust-lang/rust-clippy/pull/7350)
|
||||
* Moved [`blanket_clippy_restriction_lints`] to `suspicious`
|
||||
* Moved [`empty_loop`] to `suspicious`
|
||||
* Moved [`eval_order_dependence`] to `suspicious`
|
||||
* Moved [`float_equality_without_abs`] to `suspicious`
|
||||
* Moved [`for_loops_over_fallibles`] to `suspicious`
|
||||
* Moved [`misrefactored_assign_op`] to `suspicious`
|
||||
* Moved [`mut_range_bound`] to `suspicious`
|
||||
* Moved [`mutable_key_type`] to `suspicious`
|
||||
* Moved [`suspicious_arithmetic_impl`] to `suspicious`
|
||||
* Moved [`suspicious_assignment_formatting`] to `suspicious`
|
||||
* Moved [`suspicious_else_formatting`] to `suspicious`
|
||||
* Moved [`suspicious_map`] to `suspicious`
|
||||
* Moved [`suspicious_op_assign_impl`] to `suspicious`
|
||||
* Moved [`suspicious_unary_op_formatting`] to `suspicious`
|
||||
|
||||
### Enhancements
|
||||
|
||||
* [`while_let_on_iterator`]: Now suggests `&mut iter` inside closures
|
||||
[#7262](https://github.com/rust-lang/rust-clippy/pull/7262)
|
||||
* [`doc_markdown`]:
|
||||
* Now detects unbalanced ticks
|
||||
[#7357](https://github.com/rust-lang/rust-clippy/pull/7357)
|
||||
* Add `FreeBSD` to the default configuration as an allowed identifier
|
||||
[#7334](https://github.com/rust-lang/rust-clippy/pull/7334)
|
||||
* [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]: Now allows wildcards for enums with unstable
|
||||
or hidden variants
|
||||
[#7407](https://github.com/rust-lang/rust-clippy/pull/7407)
|
||||
* [`redundant_allocation`]: Now additionally supports the `Arc<>` type
|
||||
[#7308](https://github.com/rust-lang/rust-clippy/pull/7308)
|
||||
* [`blacklisted_name`]: Now allows blacklisted names in test code
|
||||
[#7379](https://github.com/rust-lang/rust-clippy/pull/7379)
|
||||
* [`redundant_closure`]: Suggests `&mut` for `FnMut`
|
||||
[#7437](https://github.com/rust-lang/rust-clippy/pull/7437)
|
||||
* [`disallowed_method`], [`disallowed_type`]: The configuration values `disallowed-method` and `disallowed-type`
|
||||
no longer require fully qualified paths
|
||||
[#7345](https://github.com/rust-lang/rust-clippy/pull/7345)
|
||||
* [`zst_offset`]: Fixed lint invocation after it was accidentally suppressed
|
||||
[#7396](https://github.com/rust-lang/rust-clippy/pull/7396)
|
||||
|
||||
### False Positive Fixes
|
||||
|
||||
* [`default_numeric_fallback`]: No longer lints on float literals as function arguments
|
||||
[#7446](https://github.com/rust-lang/rust-clippy/pull/7446)
|
||||
* [`use_self`]: No longer lints on type parameters
|
||||
[#7288](https://github.com/rust-lang/rust-clippy/pull/7288)
|
||||
* [`unimplemented`]: Now ignores the `assert` and `debug_assert` macros
|
||||
[#7439](https://github.com/rust-lang/rust-clippy/pull/7439)
|
||||
* [`branches_sharing_code`]: Now always checks for block expressions
|
||||
[#7462](https://github.com/rust-lang/rust-clippy/pull/7462)
|
||||
* [`field_reassign_with_default`]: No longer triggers in macros
|
||||
[#7160](https://github.com/rust-lang/rust-clippy/pull/7160)
|
||||
* [`redundant_clone`]: No longer lints on required clones for borrowed data
|
||||
[#7346](https://github.com/rust-lang/rust-clippy/pull/7346)
|
||||
* [`default_numeric_fallback`]: No longer triggers in external macros
|
||||
[#7325](https://github.com/rust-lang/rust-clippy/pull/7325)
|
||||
* [`needless_bool`]: No longer lints in macros
|
||||
[#7442](https://github.com/rust-lang/rust-clippy/pull/7442)
|
||||
* [`useless_format`]: No longer triggers when additional text is being appended
|
||||
[#7442](https://github.com/rust-lang/rust-clippy/pull/7442)
|
||||
* [`assertions_on_constants`]: `cfg!(...)` is no longer considered to be a constant
|
||||
[#7319](https://github.com/rust-lang/rust-clippy/pull/7319)
|
||||
|
||||
### Suggestion Fixes/Improvements
|
||||
|
||||
* [`needless_collect`]: Now show correct lint messages for shadowed values
|
||||
[#7289](https://github.com/rust-lang/rust-clippy/pull/7289)
|
||||
* [`wrong_pub_self_convention`]: The deprecated message now suggest the correct configuration value
|
||||
[#7382](https://github.com/rust-lang/rust-clippy/pull/7382)
|
||||
* [`semicolon_if_nothing_returned`]: Allow missing semicolon in blocks with only one expression
|
||||
[#7326](https://github.com/rust-lang/rust-clippy/pull/7326)
|
||||
|
||||
### ICE Fixes
|
||||
|
||||
* [`zero_sized_map_values`]
|
||||
[#7470](https://github.com/rust-lang/rust-clippy/pull/7470)
|
||||
* [`redundant_pattern_matching`]
|
||||
[#7471](https://github.com/rust-lang/rust-clippy/pull/7471)
|
||||
* [`modulo_one`]
|
||||
[#7473](https://github.com/rust-lang/rust-clippy/pull/7473)
|
||||
* [`use_self`]
|
||||
[#7428](https://github.com/rust-lang/rust-clippy/pull/7428)
|
||||
|
||||
### Documentation Improvements
|
||||
|
||||
* Reworked Clippy's website:
|
||||
[#7279](https://github.com/rust-lang/rust-clippy/pull/7279)
|
||||
[#7172](https://github.com/rust-lang/rust-clippy/issues/7172)
|
||||
* Added applicability information about lints
|
||||
* Added a link to jump into the implementation
|
||||
* Improved loading times
|
||||
* Adapted some styling
|
||||
* Clippy now uses a lint to generate its documentation
|
||||
[#7298](https://github.com/rust-lang/rust-clippy/pull/7298)
|
||||
|
||||
## Rust 1.54
|
||||
|
||||
Current beta, release 2021-07-29
|
||||
Current stable, released 2021-07-29
|
||||
|
||||
[7c7683c...3ae8faf](https://github.com/rust-lang/rust-clippy/compare/7c7683c...3ae8faf)
|
||||
|
||||
@ -29,7 +159,7 @@ Current beta, release 2021-07-29
|
||||
### Moves and Deprecations
|
||||
|
||||
- Deprecate `pub_enum_variant_names` and `wrong_pub_self_convention` in favor of
|
||||
the new `avoid_breaking_exported_api` config option (see
|
||||
the new `avoid-breaking-exported-api` config option (see
|
||||
[Enhancements](#1-54-enhancements))
|
||||
[#7187](https://github.com/rust-lang/rust-clippy/pull/7187)
|
||||
- Move [`inconsistent_struct_constructor`] to `pedantic`
|
||||
@ -51,7 +181,7 @@ Current beta, release 2021-07-29
|
||||
[#7163](https://github.com/rust-lang/rust-clippy/pull/7163)
|
||||
- [`if_then_some_else_none`]: Now works with the MSRV config
|
||||
[#7177](https://github.com/rust-lang/rust-clippy/pull/7177)
|
||||
- Add `avoid_breaking_exported_api` config option for the lints
|
||||
- Add `avoid-breaking-exported-api` config option for the lints
|
||||
[`enum_variant_names`], [`large_types_passed_by_value`],
|
||||
[`trivially_copy_pass_by_ref`], [`unnecessary_wraps`],
|
||||
[`upper_case_acronyms`], and [`wrong_self_convention`]. We recommend to set
|
||||
@ -138,7 +268,7 @@ Current beta, release 2021-07-29
|
||||
|
||||
## Rust 1.53
|
||||
|
||||
Current stable, released 2021-06-17
|
||||
Released 2021-06-17
|
||||
|
||||
[6ed6f1e...7c7683c](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...7c7683c)
|
||||
|
||||
@ -2869,6 +2999,7 @@ Released 2018-09-13
|
||||
[`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
|
||||
[`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
|
||||
[`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result
|
||||
[`unwrap_or_else_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_else_default
|
||||
[`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
|
||||
[`upper_case_acronyms`]: https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms
|
||||
[`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_ast::ast::{Expr, ExprKind};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
@ -47,7 +47,7 @@ declare_lint_pass!(AsConversions => [AS_CONVERSIONS]);
|
||||
|
||||
impl EarlyLintPass for AsConversions {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
if in_external_macro(cx.sess, expr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -230,15 +230,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
||||
panic_span: None,
|
||||
};
|
||||
fpu.visit_expr(&body.value);
|
||||
lint_for_missing_headers(
|
||||
cx,
|
||||
item.def_id,
|
||||
item.span,
|
||||
sig,
|
||||
headers,
|
||||
Some(body_id),
|
||||
fpu.panic_span,
|
||||
);
|
||||
lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
|
||||
}
|
||||
},
|
||||
hir::ItemKind::Impl(ref impl_) => {
|
||||
@ -278,15 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
||||
panic_span: None,
|
||||
};
|
||||
fpu.visit_expr(&body.value);
|
||||
lint_for_missing_headers(
|
||||
cx,
|
||||
item.def_id,
|
||||
item.span,
|
||||
sig,
|
||||
headers,
|
||||
Some(body_id),
|
||||
fpu.panic_span,
|
||||
);
|
||||
lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_ast::ast::{Expr, ExprKind};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
@ -49,7 +49,7 @@ declare_lint_pass!(ElseIfWithoutElse => [ELSE_IF_WITHOUT_ELSE]);
|
||||
|
||||
impl EarlyLintPass for ElseIfWithoutElse {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, mut item: &Expr) {
|
||||
if in_external_macro(cx.sess(), item.span) {
|
||||
if in_external_macro(cx.sess, item.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -251,7 +251,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
|
||||
hir_id: hir::HirId,
|
||||
) {
|
||||
too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold);
|
||||
too_many_lines::check_fn(cx, span, body, self.too_many_lines_threshold);
|
||||
too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold);
|
||||
not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, hir_id);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_span::Span;
|
||||
@ -8,8 +9,16 @@ use clippy_utils::source::snippet_opt;
|
||||
|
||||
use super::TOO_MANY_LINES;
|
||||
|
||||
pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<'_>, too_many_lines_threshold: u64) {
|
||||
if in_external_macro(cx.sess(), span) {
|
||||
pub(super) fn check_fn(
|
||||
cx: &LateContext<'_>,
|
||||
kind: FnKind<'tcx>,
|
||||
span: Span,
|
||||
body: &'tcx hir::Body<'_>,
|
||||
too_many_lines_threshold: u64,
|
||||
) {
|
||||
// Closures must be contained in a parent body, which will be checked for `too_many_lines`.
|
||||
// Don't check closures for `too_many_lines` to avoid duplicated lints.
|
||||
if matches!(kind, FnKind::Closure) || in_external_macro(cx.sess(), span) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
@ -48,7 +48,7 @@ declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
|
||||
|
||||
impl EarlyLintPass for IfNotElse {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
|
||||
if in_external_macro(cx.sess(), item.span) {
|
||||
if in_external_macro(cx.sess, item.span) {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::If(ref cond, _, Some(ref els)) = item.kind {
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_ast::ast::{Block, ItemKind, StmtKind};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
@ -54,7 +54,7 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]);
|
||||
|
||||
impl EarlyLintPass for ItemsAfterStatements {
|
||||
fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) {
|
||||
if in_external_macro(cx.sess(), item.span) {
|
||||
if in_external_macro(cx.sess, item.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ impl EarlyLintPass for ItemsAfterStatements {
|
||||
// lint on all further items
|
||||
for stmt in stmts {
|
||||
if let StmtKind::Item(ref it) = *stmt {
|
||||
if in_external_macro(cx.sess(), it.span) {
|
||||
if in_external_macro(cx.sess, it.span) {
|
||||
return;
|
||||
}
|
||||
if let ItemKind::MacroDef(..) = it.kind {
|
||||
|
@ -207,8 +207,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
|
||||
}
|
||||
}
|
||||
|
||||
if cx.access_levels.is_exported(visited_trait.def_id)
|
||||
&& trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
|
||||
if cx.access_levels.is_exported(visited_trait.def_id) && trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
|
||||
{
|
||||
let mut current_and_super_traits = DefIdSet::default();
|
||||
fill_trait_set(visited_trait.def_id.to_def_id(), &mut current_and_super_traits, cx);
|
||||
@ -331,17 +330,15 @@ fn check_for_is_empty(
|
||||
None,
|
||||
None,
|
||||
),
|
||||
Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => {
|
||||
(
|
||||
format!(
|
||||
"{} `{}` has a public `len` method, but a private `is_empty` method",
|
||||
item_kind,
|
||||
item_name.as_str(),
|
||||
),
|
||||
Some(cx.tcx.def_span(is_empty.def_id)),
|
||||
None,
|
||||
)
|
||||
},
|
||||
Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => (
|
||||
format!(
|
||||
"{} `{}` has a public `len` method, but a private `is_empty` method",
|
||||
item_kind,
|
||||
item_name.as_str(),
|
||||
),
|
||||
Some(cx.tcx.def_span(is_empty.def_id)),
|
||||
None,
|
||||
),
|
||||
Some(is_empty)
|
||||
if !(is_empty.fn_has_self_parameter
|
||||
&& check_is_empty_sig(cx.tcx.fn_sig(is_empty.def_id).skip_binder(), self_kind, output)) =>
|
||||
|
@ -797,6 +797,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
methods::UNNECESSARY_FILTER_MAP,
|
||||
methods::UNNECESSARY_FOLD,
|
||||
methods::UNNECESSARY_LAZY_EVALUATIONS,
|
||||
methods::UNWRAP_OR_ELSE_DEFAULT,
|
||||
methods::UNWRAP_USED,
|
||||
methods::USELESS_ASREF,
|
||||
methods::WRONG_SELF_CONVENTION,
|
||||
@ -1341,6 +1342,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(methods::UNNECESSARY_FILTER_MAP),
|
||||
LintId::of(methods::UNNECESSARY_FOLD),
|
||||
LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
|
||||
LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
|
||||
LintId::of(methods::USELESS_ASREF),
|
||||
LintId::of(methods::WRONG_SELF_CONVENTION),
|
||||
LintId::of(methods::ZST_OFFSET),
|
||||
@ -1535,6 +1537,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(methods::STRING_EXTEND_CHARS),
|
||||
LintId::of(methods::UNNECESSARY_FOLD),
|
||||
LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
|
||||
LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
|
||||
LintId::of(methods::WRONG_SELF_CONVENTION),
|
||||
LintId::of(misc::TOPLEVEL_REF_ARG),
|
||||
LintId::of(misc::ZERO_PTR),
|
||||
|
@ -10,7 +10,7 @@ use clippy_utils::{
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use std::iter;
|
||||
@ -222,7 +222,7 @@ impl_lint_pass!(LiteralDigitGrouping => [
|
||||
|
||||
impl EarlyLintPass for LiteralDigitGrouping {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
if in_external_macro(cx.sess, expr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -415,7 +415,7 @@ impl_lint_pass!(DecimalLiteralRepresentation => [DECIMAL_LITERAL_REPRESENTATION]
|
||||
|
||||
impl EarlyLintPass for DecimalLiteralRepresentation {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
if in_external_macro(cx.sess, expr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -204,11 +204,8 @@ struct MinifyingSugg<'a>(Sugg<'a>);
|
||||
|
||||
impl<'a> MinifyingSugg<'a> {
|
||||
fn as_str(&self) -> &str {
|
||||
// HACK: Don't sync to Clippy! Required because something with the `or_patterns` feature
|
||||
// changed and this would now require parentheses.
|
||||
match &self.0 {
|
||||
Sugg::NonParen(s) | Sugg::MaybeParen(s) | Sugg::BinOp(_, s) => s.as_ref(),
|
||||
}
|
||||
let (Sugg::NonParen(s) | Sugg::MaybeParen(s) | Sugg::BinOp(_, s)) = &self.0;
|
||||
s.as_ref()
|
||||
}
|
||||
|
||||
fn into_sugg(self) -> Sugg<'a> {
|
||||
|
@ -1,13 +1,36 @@
|
||||
use super::utils::make_iterator_snippet;
|
||||
use super::NEVER_LOOP;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, Stmt, StmtKind};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, LoopSource, Node, Pat, Stmt, StmtKind};
|
||||
use rustc_lint::LateContext;
|
||||
use std::iter::{once, Iterator};
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Loop(block, _, _, _) = expr.kind {
|
||||
if let ExprKind::Loop(block, _, source, _) = expr.kind {
|
||||
match never_loop_block(block, expr.hir_id) {
|
||||
NeverLoopResult::AlwaysBreak => span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"),
|
||||
NeverLoopResult::AlwaysBreak => {
|
||||
span_lint_and_then(cx, NEVER_LOOP, expr.span, "this loop never actually loops", |diag| {
|
||||
if_chain! {
|
||||
if let LoopSource::ForLoop = source;
|
||||
if let Some((_, Node::Expr(parent_match))) = cx.tcx.hir().parent_iter(expr.hir_id).nth(1);
|
||||
if let Some((pat, iterator, _, for_span)) = higher::for_loop(parent_match);
|
||||
then {
|
||||
// Suggests using an `if let` instead. This is `Unspecified` because the
|
||||
// loop may (probably) contain `break` statements which would be invalid
|
||||
// in an `if let`.
|
||||
diag.span_suggestion_verbose(
|
||||
for_span.with_hi(iterator.span.hi()),
|
||||
"if you need the first element of the iterator, try writing",
|
||||
for_to_if_let_sugg(cx, iterator, pat),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
|
||||
}
|
||||
}
|
||||
@ -170,3 +193,14 @@ fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(e: &mut T, main_
|
||||
e.map(|e| never_loop_expr(e, main_loop_id))
|
||||
.fold(NeverLoopResult::AlwaysBreak, combine_branches)
|
||||
}
|
||||
|
||||
fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) -> String {
|
||||
let pat_snippet = snippet(cx, pat.span, "_");
|
||||
let iter_snippet = make_iterator_snippet(cx, iterator, &mut Applicability::Unspecified);
|
||||
|
||||
format!(
|
||||
"if let Some({pat}) = {iter}.next()",
|
||||
pat = pat_snippet,
|
||||
iter = iter_snippet
|
||||
)
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use clippy_utils::{
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, MatchSource, Node, PatKind, QPath, UnOp};
|
||||
use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, MatchSource, Mutability, Node, PatKind, QPath, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::{symbol::sym, Span, Symbol};
|
||||
|
||||
@ -48,7 +48,12 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
// borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used
|
||||
// afterwards a mutable borrow of a field isn't necessary.
|
||||
let ref_mut = if !iter_expr.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr, loop_expr) {
|
||||
"&mut "
|
||||
if cx.typeck_results().node_type(iter_expr.hir_id).ref_mutability() == Some(Mutability::Mut) {
|
||||
// Reborrow for mutable references. It may not be possible to get a mutable reference here.
|
||||
"&mut *"
|
||||
} else {
|
||||
"&mut "
|
||||
}
|
||||
} else {
|
||||
""
|
||||
};
|
||||
@ -69,6 +74,8 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
struct IterExpr {
|
||||
/// The span of the whole expression, not just the path and fields stored here.
|
||||
span: Span,
|
||||
/// The HIR id of the whole expression, not just the path and fields stored here.
|
||||
hir_id: HirId,
|
||||
/// The fields used, in order of child to parent.
|
||||
fields: Vec<Symbol>,
|
||||
/// The path being used.
|
||||
@ -78,12 +85,14 @@ struct IterExpr {
|
||||
/// the expression might have side effects.
|
||||
fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExpr> {
|
||||
let span = e.span;
|
||||
let hir_id = e.hir_id;
|
||||
let mut fields = Vec::new();
|
||||
loop {
|
||||
match e.kind {
|
||||
ExprKind::Path(ref path) => {
|
||||
break Some(IterExpr {
|
||||
span,
|
||||
hir_id,
|
||||
fields,
|
||||
path: cx.qpath_res(path, e.hir_id),
|
||||
});
|
||||
@ -137,7 +146,7 @@ fn is_expr_same_child_or_parent_field(cx: &LateContext<'_>, expr: &Expr<'_>, fie
|
||||
match expr.kind {
|
||||
ExprKind::Field(base, name) => {
|
||||
if let Some((head_field, tail_fields)) = fields.split_first() {
|
||||
if name.name == *head_field && is_expr_same_field(cx, base, fields, path_res) {
|
||||
if name.name == *head_field && is_expr_same_field(cx, base, tail_fields, path_res) {
|
||||
return true;
|
||||
}
|
||||
// Check if the expression is a parent field
|
||||
|
@ -16,7 +16,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
|
||||
//check source object
|
||||
if let ExprKind::MethodCall(src_method, _, [drain_vec, drain_arg], _) = &arg.kind;
|
||||
if src_method.ident.as_str() == "drain";
|
||||
if let src_ty = cx.typeck_results().expr_ty(drain_vec).peel_refs();
|
||||
let src_ty = cx.typeck_results().expr_ty(drain_vec);
|
||||
//check if actual src type is mutable for code suggestion
|
||||
let immutable = src_ty.is_mutable_ptr();
|
||||
let src_ty = src_ty.peel_refs();
|
||||
if is_type_diagnostic_item(cx, src_ty, sym::vec_type);
|
||||
//check drain range
|
||||
if let src_ty_range = cx.typeck_results().expr_ty(drain_arg).peel_refs();
|
||||
@ -30,8 +33,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
|
||||
"use of `extend` instead of `append` for adding the full range of a second vector",
|
||||
"try this",
|
||||
format!(
|
||||
"{}.append(&mut {})",
|
||||
"{}.append({}{})",
|
||||
snippet_with_applicability(cx, recv.span, "..", &mut applicability),
|
||||
if immutable { "" } else { "&mut " },
|
||||
snippet_with_applicability(cx, drain_vec.span, "..", &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
|
@ -1,10 +1,11 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{is_expr_path_def_path, paths, sugg};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::sym;
|
||||
|
||||
@ -43,7 +44,7 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -
|
||||
|
||||
let call_site = expr.span.source_callsite();
|
||||
if_chain! {
|
||||
if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site);
|
||||
if let Some(snippet) = snippet_opt(cx, call_site);
|
||||
let snippet_split = snippet.split("::").collect::<Vec<_>>();
|
||||
if let Some((_, elements)) = snippet_split.split_last();
|
||||
|
||||
|
@ -52,18 +52,32 @@ pub(super) fn check<'tcx>(
|
||||
);
|
||||
}
|
||||
|
||||
// lint if caller of `.map().flatten()` is an Option
|
||||
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type) {
|
||||
let func_snippet = snippet(cx, map_arg.span, "..");
|
||||
let hint = format!(".and_then({})", func_snippet);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MAP_FLATTEN,
|
||||
expr.span.with_lo(recv.span.hi()),
|
||||
"called `map(..).flatten()` on an `Option`",
|
||||
"try using `and_then` instead",
|
||||
hint,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
// lint if caller of `.map().flatten()` is an Option or Result
|
||||
let caller_type = match cx.typeck_results().expr_ty(recv).kind() {
|
||||
ty::Adt(adt, _) => {
|
||||
if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) {
|
||||
"Option"
|
||||
} else if cx.tcx.is_diagnostic_item(sym::result_type, adt.did) {
|
||||
"Result"
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
let func_snippet = snippet(cx, map_arg.span, "..");
|
||||
let hint = format!(".and_then({})", func_snippet);
|
||||
let lint_info = format!("called `map(..).flatten()` on an `{}`", caller_type);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MAP_FLATTEN,
|
||||
expr.span.with_lo(recv.span.hi()),
|
||||
&lint_info,
|
||||
"try using `and_then` instead",
|
||||
hint,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ mod uninit_assumed_init;
|
||||
mod unnecessary_filter_map;
|
||||
mod unnecessary_fold;
|
||||
mod unnecessary_lazy_eval;
|
||||
mod unwrap_or_else_default;
|
||||
mod unwrap_used;
|
||||
mod useless_asref;
|
||||
mod utils;
|
||||
@ -310,6 +311,31 @@ declare_clippy_lint! {
|
||||
"using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and
|
||||
/// `Result` values.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Readability, these can be written as `_.unwrap_or_default`, which is
|
||||
/// simpler and more concise.
|
||||
///
|
||||
/// ### Examples
|
||||
/// ```rust
|
||||
/// # let x = Some(1);
|
||||
///
|
||||
/// // Bad
|
||||
/// x.unwrap_or_else(Default::default);
|
||||
/// x.unwrap_or_else(u32::default);
|
||||
///
|
||||
/// // Good
|
||||
/// x.unwrap_or_default();
|
||||
/// ```
|
||||
pub UNWRAP_OR_ELSE_DEFAULT,
|
||||
style,
|
||||
"using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or
|
||||
@ -1766,6 +1792,7 @@ impl_lint_pass!(Methods => [
|
||||
SHOULD_IMPLEMENT_TRAIT,
|
||||
WRONG_SELF_CONVENTION,
|
||||
OK_EXPECT,
|
||||
UNWRAP_OR_ELSE_DEFAULT,
|
||||
MAP_UNWRAP_OR,
|
||||
RESULT_MAP_OR_INTO_OPTION,
|
||||
OPTION_MAP_OR_NONE,
|
||||
@ -2172,7 +2199,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
|
||||
},
|
||||
("unwrap_or_else", [u_arg]) => match method_call!(recv) {
|
||||
Some(("map", [recv, map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, msrv) => {},
|
||||
_ => unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"),
|
||||
_ => {
|
||||
unwrap_or_else_default::check(cx, expr, recv, u_arg);
|
||||
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
|
||||
},
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::eager_or_lazy::is_lazyness_candidate;
|
||||
use clippy_utils::is_trait_item;
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite};
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type};
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, match_type};
|
||||
use clippy_utils::{contains_return, last_path_segment, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
@ -34,15 +36,23 @@ pub(super) fn check<'tcx>(
|
||||
or_has_args: bool,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
let is_default_default = || is_trait_item(cx, fun, sym::Default);
|
||||
|
||||
let implements_default = |arg, default_trait_id| {
|
||||
let arg_ty = cx.typeck_results().expr_ty(arg);
|
||||
implements_trait(cx, arg_ty, default_trait_id, &[])
|
||||
};
|
||||
|
||||
if_chain! {
|
||||
if !or_has_args;
|
||||
if name == "unwrap_or";
|
||||
if let hir::ExprKind::Path(ref qpath) = fun.kind;
|
||||
let path = last_path_segment(qpath).ident.name;
|
||||
if matches!(path, kw::Default | sym::new);
|
||||
let arg_ty = cx.typeck_results().expr_ty(arg);
|
||||
if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
|
||||
if implements_trait(cx, arg_ty, default_trait_id, &[]);
|
||||
let path = last_path_segment(qpath).ident.name;
|
||||
// needs to target Default::default in particular or be *::new and have a Default impl
|
||||
// available
|
||||
if (matches!(path, kw::Default) && is_default_default())
|
||||
|| (matches!(path, sym::new) && implements_default(arg, default_trait_id));
|
||||
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
45
clippy_lints/src/methods/unwrap_or_else_default.rs
Normal file
45
clippy_lints/src/methods/unwrap_or_else_default.rs
Normal file
@ -0,0 +1,45 @@
|
||||
//! Lint for `some_result_or_option.unwrap_or_else(Default::default)`
|
||||
|
||||
use super::UNWRAP_OR_ELSE_DEFAULT;
|
||||
use clippy_utils::{
|
||||
diagnostics::span_lint_and_sugg, is_trait_item, source::snippet_with_applicability, ty::is_type_diagnostic_item,
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'_>,
|
||||
recv: &'tcx hir::Expr<'_>,
|
||||
u_arg: &'tcx hir::Expr<'_>,
|
||||
) {
|
||||
// something.unwrap_or_else(Default::default)
|
||||
// ^^^^^^^^^- recv ^^^^^^^^^^^^^^^^- u_arg
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr
|
||||
let recv_ty = cx.typeck_results().expr_ty(recv);
|
||||
let is_option = is_type_diagnostic_item(cx, recv_ty, sym::option_type);
|
||||
let is_result = is_type_diagnostic_item(cx, recv_ty, sym::result_type);
|
||||
|
||||
if_chain! {
|
||||
if is_option || is_result;
|
||||
if is_trait_item(cx, u_arg, sym::Default);
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNWRAP_OR_ELSE_DEFAULT,
|
||||
expr.span,
|
||||
"use of `.unwrap_or_else(..)` to construct default value",
|
||||
"try",
|
||||
format!(
|
||||
"{}.unwrap_or_default()",
|
||||
snippet_with_applicability(cx, recv.span, "..", &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ use clippy_utils::source::snippet_opt;
|
||||
use rustc_ast::ast::{Expr, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
|
||||
use rustc_ast::visit::FnKind;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
@ -307,7 +307,7 @@ impl EarlyLintPass for MiscEarlyLints {
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
if in_external_macro(cx.sess, expr.span) {
|
||||
return;
|
||||
}
|
||||
double_neg::check(cx, expr);
|
||||
|
@ -1,6 +1,7 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use rustc_ast::ast::{Pat, PatKind};
|
||||
use rustc_lint::{EarlyContext, LintContext};
|
||||
use rustc_lint::EarlyContext;
|
||||
|
||||
use super::UNNEEDED_FIELD_PATTERN;
|
||||
|
||||
@ -48,7 +49,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
|
||||
match field.pat.kind {
|
||||
PatKind::Wild => {},
|
||||
_ => {
|
||||
if let Ok(n) = cx.sess().source_map().span_to_snippet(field.span) {
|
||||
if let Some(n) = snippet_opt(cx, field.span) {
|
||||
normal.push(n);
|
||||
}
|
||||
},
|
||||
|
@ -7,7 +7,8 @@
|
||||
|
||||
use clippy_utils::attrs::is_doc_hidden;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_ast::ast;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{self, MetaItem, MetaItemKind};
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::ty;
|
||||
@ -55,6 +56,20 @@ impl MissingDoc {
|
||||
*self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
|
||||
}
|
||||
|
||||
fn has_include(meta: Option<MetaItem>) -> bool {
|
||||
if_chain! {
|
||||
if let Some(meta) = meta;
|
||||
if let MetaItemKind::List(list) = meta.kind;
|
||||
if let Some(meta) = list.get(0);
|
||||
if let Some(name) = meta.ident();
|
||||
then {
|
||||
name.name == sym::include
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_missing_docs_attrs(
|
||||
&self,
|
||||
cx: &LateContext<'_>,
|
||||
@ -80,7 +95,7 @@ impl MissingDoc {
|
||||
|
||||
let has_doc = attrs
|
||||
.iter()
|
||||
.any(|a| a.doc_str().is_some());
|
||||
.any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
|
||||
if !has_doc {
|
||||
span_lint(
|
||||
cx,
|
||||
|
@ -87,10 +87,6 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
|
||||
self.found = true;
|
||||
return;
|
||||
},
|
||||
ExprKind::If(..) => {
|
||||
self.found = true;
|
||||
return;
|
||||
},
|
||||
ExprKind::Path(_) => {
|
||||
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
|
||||
if adj
|
||||
|
@ -27,11 +27,15 @@ declare_clippy_lint! {
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// fn fun(_a: &i32) {}
|
||||
///
|
||||
/// // Bad
|
||||
/// let x: &i32 = &&&&&&5;
|
||||
/// fun(&x);
|
||||
///
|
||||
/// // Good
|
||||
/// let x: &i32 = &5;
|
||||
/// fun(x);
|
||||
/// ```
|
||||
pub NEEDLESS_BORROW,
|
||||
style,
|
||||
|
@ -422,7 +422,7 @@ fn check_and_warn<'a>(cx: &EarlyContext<'_>, expr: &'a ast::Expr) {
|
||||
///
|
||||
/// is transformed to
|
||||
///
|
||||
/// ```ignore
|
||||
/// ```text
|
||||
/// {
|
||||
/// let x = 5;
|
||||
/// ```
|
||||
|
@ -122,7 +122,7 @@ impl LateLintPass<'_> for NeedlessForEach {
|
||||
/// 2. Detect use of `return` in `Loop` in the closure body.
|
||||
///
|
||||
/// NOTE: The functionality of this type is similar to
|
||||
/// [`crate::utilts::visitors::find_all_ret_expressions`], but we can't use
|
||||
/// [`clippy_utils::visitors::find_all_ret_expressions`], but we can't use
|
||||
/// `find_all_ret_expressions` instead of this type. The reasons are:
|
||||
/// 1. `find_all_ret_expressions` passes the argument of `ExprKind::Ret` to a callback, but what we
|
||||
/// need here is `ExprKind::Ret` itself.
|
||||
|
@ -3,7 +3,7 @@ use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::has_drop;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource};
|
||||
use rustc_hir::{is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use std::ops::Deref;
|
||||
@ -68,12 +68,14 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
ExprKind::Call(callee, args) => {
|
||||
if let ExprKind::Path(ref qpath) = callee.kind {
|
||||
let res = cx.qpath_res(qpath, callee.hir_id);
|
||||
match res {
|
||||
Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..) => {
|
||||
!has_drop(cx, cx.typeck_results().expr_ty(expr))
|
||||
&& args.iter().all(|arg| has_no_effect(cx, arg))
|
||||
},
|
||||
_ => false,
|
||||
let def_matched = matches!(
|
||||
res,
|
||||
Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..)
|
||||
);
|
||||
if def_matched || is_range_literal(expr) {
|
||||
!has_drop(cx, cx.typeck_results().expr_ty(expr)) && args.iter().all(|arg| has_no_effect(cx, arg))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
|
@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
||||
use rustc_ast::ast::{
|
||||
Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, FnKind, Item, ItemKind, Local, Pat,
|
||||
PatKind,
|
||||
Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, FnKind, Item, ItemKind, Local, Pat, PatKind,
|
||||
};
|
||||
use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
@ -127,6 +126,7 @@ const ALLOWED_TO_BE_SIMILAR: &[&[&str]] = &[
|
||||
&["qpath", "path"],
|
||||
&["lit", "lint"],
|
||||
&["wparam", "lparam"],
|
||||
&["iter", "item"],
|
||||
];
|
||||
|
||||
struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>);
|
||||
|
@ -7,6 +7,7 @@ use clippy_utils::{diagnostics::span_lint_and_help, in_macro, is_direct_expn_of,
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::Span;
|
||||
@ -91,13 +92,23 @@ impl EarlyLintPass for MacroBraces {
|
||||
}
|
||||
|
||||
fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a MacroBraces) -> Option<MacroInfo<'a>> {
|
||||
let unnested_or_local = || {
|
||||
let nested = in_macro(span.ctxt().outer_expn_data().call_site);
|
||||
!nested
|
||||
|| span
|
||||
.macro_backtrace()
|
||||
.last()
|
||||
.map_or(false, |e| e.macro_def_id.map_or(false, DefId::is_local))
|
||||
};
|
||||
if_chain! {
|
||||
// Make sure we are only one level deep otherwise there are to many FP's
|
||||
if in_macro(span);
|
||||
if let Some((name, braces)) = find_matching_macro(span, &mac_braces.macro_braces);
|
||||
if let Some(snip) = snippet_opt(cx, span.ctxt().outer_expn_data().call_site);
|
||||
// we must check only invocation sites
|
||||
// https://github.com/rust-lang/rust-clippy/issues/7422
|
||||
if snip.starts_with(name);
|
||||
if snip.starts_with(&format!("{}!", name));
|
||||
if unnested_or_local();
|
||||
// make formatting consistent
|
||||
let c = snip.replace(" ", "");
|
||||
if !c.starts_with(&format!("{}!{}", name, braces.0));
|
||||
|
@ -2,9 +2,9 @@ use std::cmp;
|
||||
use std::iter;
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_self_ty;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_copy;
|
||||
use clippy_utils::{is_self, is_self_ty};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::attr;
|
||||
use rustc_errors::Applicability;
|
||||
@ -170,7 +170,7 @@ impl<'tcx> PassByRefOrValue {
|
||||
if size <= self.ref_min_size;
|
||||
if let hir::TyKind::Rptr(_, MutTy { ty: decl_ty, .. }) = input.kind;
|
||||
then {
|
||||
let value_type = if is_self_ty(decl_ty) {
|
||||
let value_type = if fn_body.and_then(|body| body.params.get(index)).map_or(false, is_self) {
|
||||
"self".into()
|
||||
} else {
|
||||
snippet(cx, decl_ty.span, "_").into()
|
||||
|
@ -725,7 +725,7 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
|
||||
BinaryOp(_, box (lhs, rhs)) | CheckedBinaryOp(_, box (lhs, rhs)) => {
|
||||
visit_op(lhs);
|
||||
visit_op(rhs);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit as hir_visit;
|
||||
use rustc_hir::intravisit::Visitor as HirVisitor;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -63,7 +63,7 @@ impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor {
|
||||
|
||||
impl EarlyLintPass for RedundantClosureCall {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
if in_external_macro(cx.sess, expr.span) {
|
||||
return;
|
||||
}
|
||||
if_chain! {
|
||||
|
@ -54,7 +54,8 @@ impl EarlyLintPass for DerefAddrOf {
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let sugg = if e.span.from_expansion() {
|
||||
if let Ok(macro_source) = cx.sess.source_map().span_to_snippet(e.span) {
|
||||
#[allow(clippy::option_if_let_else)]
|
||||
if let Some(macro_source) = snippet_opt(cx, e.span) {
|
||||
// Remove leading whitespace from the given span
|
||||
// e.g: ` $visitor` turns into `$visitor`
|
||||
let trim_leading_whitespaces = |span| {
|
||||
|
@ -1,15 +1,16 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{differing_macro_contexts, eq_expr_value};
|
||||
use clippy_utils::{can_mut_borrow_both, differing_macro_contexts, eq_expr_value};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, StmtKind};
|
||||
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@ -70,9 +71,67 @@ impl<'tcx> LateLintPass<'tcx> for Swap {
|
||||
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
|
||||
check_manual_swap(cx, block);
|
||||
check_suspicious_swap(cx, block);
|
||||
check_xor_swap(cx, block);
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, span: Span, is_xor_based: bool) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
if !can_mut_borrow_both(cx, e1, e2) {
|
||||
if let ExprKind::Index(lhs1, idx1) = e1.kind {
|
||||
if let ExprKind::Index(lhs2, idx2) = e2.kind {
|
||||
if eq_expr_value(cx, lhs1, lhs2) {
|
||||
let ty = cx.typeck_results().expr_ty(lhs1).peel_refs();
|
||||
|
||||
if matches!(ty.kind(), ty::Slice(_))
|
||||
|| matches!(ty.kind(), ty::Array(_, _))
|
||||
|| is_type_diagnostic_item(cx, ty, sym::vec_type)
|
||||
|| is_type_diagnostic_item(cx, ty, sym::vecdeque_type)
|
||||
{
|
||||
let slice = Sugg::hir_with_applicability(cx, lhs1, "<slice>", &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_SWAP,
|
||||
span,
|
||||
&format!("this looks like you are swapping elements of `{}` manually", slice),
|
||||
"try",
|
||||
format!(
|
||||
"{}.swap({}, {})",
|
||||
slice.maybe_par(),
|
||||
snippet_with_applicability(cx, idx1.span, "..", &mut applicability),
|
||||
snippet_with_applicability(cx, idx2.span, "..", &mut applicability),
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let first = Sugg::hir_with_applicability(cx, e1, "..", &mut applicability);
|
||||
let second = Sugg::hir_with_applicability(cx, e2, "..", &mut applicability);
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MANUAL_SWAP,
|
||||
span,
|
||||
&format!("this looks like you are swapping `{}` and `{}` manually", first, second),
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"try",
|
||||
format!("std::mem::swap({}, {})", first.mut_addr(), second.mut_addr()),
|
||||
applicability,
|
||||
);
|
||||
if !is_xor_based {
|
||||
diag.note("or maybe you should use `std::mem::replace`?");
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Implementation of the `MANUAL_SWAP` lint.
|
||||
fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||
for w in block.stmts.windows(3) {
|
||||
@ -96,123 +155,13 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||
if eq_expr_value(cx, tmp_init, lhs1);
|
||||
if eq_expr_value(cx, rhs1, lhs2);
|
||||
then {
|
||||
if let ExprKind::Field(lhs1, _) = lhs1.kind {
|
||||
if let ExprKind::Field(lhs2, _) = lhs2.kind {
|
||||
if lhs1.hir_id.owner == lhs2.hir_id.owner {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
let slice = check_for_slice(cx, lhs1, lhs2);
|
||||
let (replace, what, sugg) = if let Slice::NotSwappable = slice {
|
||||
return;
|
||||
} else if let Slice::Swappable(slice, idx1, idx2) = slice {
|
||||
if let Some(slice) = Sugg::hir_opt(cx, slice) {
|
||||
(
|
||||
false,
|
||||
format!(" elements of `{}`", slice),
|
||||
format!(
|
||||
"{}.swap({}, {})",
|
||||
slice.maybe_par(),
|
||||
snippet_with_applicability(cx, idx1.span, "..", &mut applicability),
|
||||
snippet_with_applicability(cx, idx2.span, "..", &mut applicability),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
(false, String::new(), String::new())
|
||||
}
|
||||
} else if let (Some(first), Some(second)) = (Sugg::hir_opt(cx, lhs1), Sugg::hir_opt(cx, rhs1)) {
|
||||
(
|
||||
true,
|
||||
format!(" `{}` and `{}`", first, second),
|
||||
format!("std::mem::swap({}, {})", first.mut_addr(), second.mut_addr()),
|
||||
)
|
||||
} else {
|
||||
(true, String::new(), String::new())
|
||||
};
|
||||
|
||||
let span = w[0].span.to(second.span);
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MANUAL_SWAP,
|
||||
span,
|
||||
&format!("this looks like you are swapping{} manually", what),
|
||||
|diag| {
|
||||
if !sugg.is_empty() {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"try",
|
||||
sugg,
|
||||
applicability,
|
||||
);
|
||||
|
||||
if replace {
|
||||
diag.note("or maybe you should use `std::mem::replace`?");
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
generate_swap_warning(cx, lhs1, lhs2, span, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Slice<'a> {
|
||||
/// `slice.swap(idx1, idx2)` can be used
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # let mut a = vec![0, 1];
|
||||
/// let t = a[1];
|
||||
/// a[1] = a[0];
|
||||
/// a[0] = t;
|
||||
/// // can be written as
|
||||
/// a.swap(0, 1);
|
||||
/// ```
|
||||
Swappable(&'a Expr<'a>, &'a Expr<'a>, &'a Expr<'a>),
|
||||
/// The `swap` function cannot be used.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # let mut a = [vec![1, 2], vec![3, 4]];
|
||||
/// let t = a[0][1];
|
||||
/// a[0][1] = a[1][0];
|
||||
/// a[1][0] = t;
|
||||
/// ```
|
||||
NotSwappable,
|
||||
/// Not a slice
|
||||
None,
|
||||
}
|
||||
|
||||
/// Checks if both expressions are index operations into "slice-like" types.
|
||||
fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr<'_>) -> Slice<'a> {
|
||||
if let ExprKind::Index(lhs1, idx1) = lhs1.kind {
|
||||
if let ExprKind::Index(lhs2, idx2) = lhs2.kind {
|
||||
if eq_expr_value(cx, lhs1, lhs2) {
|
||||
let ty = cx.typeck_results().expr_ty(lhs1).peel_refs();
|
||||
|
||||
if matches!(ty.kind(), ty::Slice(_))
|
||||
|| matches!(ty.kind(), ty::Array(_, _))
|
||||
|| is_type_diagnostic_item(cx, ty, sym::vec_type)
|
||||
|| is_type_diagnostic_item(cx, ty, sym::vecdeque_type)
|
||||
{
|
||||
return Slice::Swappable(lhs1, idx1, idx2);
|
||||
}
|
||||
} else {
|
||||
return Slice::NotSwappable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Slice::None
|
||||
}
|
||||
|
||||
/// Implementation of the `ALMOST_SWAPPED` lint.
|
||||
fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||
for w in block.stmts.windows(2) {
|
||||
@ -262,3 +211,40 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of the xor case for `MANUAL_SWAP` lint.
|
||||
fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||
for window in block.stmts.windows(3) {
|
||||
if_chain! {
|
||||
if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(&window[0]);
|
||||
if let Some((lhs1, rhs1)) = extract_sides_of_xor_assign(&window[1]);
|
||||
if let Some((lhs2, rhs2)) = extract_sides_of_xor_assign(&window[2]);
|
||||
if eq_expr_value(cx, lhs0, rhs1);
|
||||
if eq_expr_value(cx, lhs2, rhs1);
|
||||
if eq_expr_value(cx, lhs1, rhs0);
|
||||
if eq_expr_value(cx, lhs1, rhs2);
|
||||
then {
|
||||
let span = window[0].span.to(window[2].span);
|
||||
generate_swap_warning(cx, lhs0, rhs0, span, true);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the lhs and rhs of an xor assignment statement.
|
||||
fn extract_sides_of_xor_assign<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(&'a Expr<'hir>, &'a Expr<'hir>)> {
|
||||
if let StmtKind::Semi(expr) = stmt.kind {
|
||||
if let ExprKind::AssignOp(
|
||||
Spanned {
|
||||
node: BinOpKind::BitXor,
|
||||
..
|
||||
},
|
||||
lhs,
|
||||
rhs,
|
||||
) = expr.kind
|
||||
{
|
||||
return Some((lhs, rhs));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ declare_clippy_lint! {
|
||||
/// Checks for use of redundant allocations anywhere in the code.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Arc<T>>`, `Rc<Box<T>>`, Arc<&T>`, `Arc<Rc<T>>`,
|
||||
/// Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Arc<T>>`, `Rc<Box<T>>`, `Arc<&T>`, `Arc<Rc<T>>`,
|
||||
/// `Arc<Arc<T>>`, `Arc<Box<T>>`, `Box<&T>`, `Box<Rc<T>>`, `Box<Arc<T>>`, `Box<Box<T>>`, add an unnecessary level of indirection.
|
||||
///
|
||||
/// ### Example
|
||||
|
@ -35,8 +35,6 @@ declare_clippy_lint! {
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// #![feature(or_patterns)]
|
||||
///
|
||||
/// fn main() {
|
||||
/// if let Some(0 | 2) = Some(0) {}
|
||||
/// }
|
||||
|
@ -1,10 +1,10 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::position_before_rarrow;
|
||||
use clippy_utils::source::{position_before_rarrow, snippet_opt};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_ast::visit::FnKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::BytePos;
|
||||
@ -125,17 +125,16 @@ fn is_unit_expr(expr: &ast::Expr) -> bool {
|
||||
}
|
||||
|
||||
fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
|
||||
let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) {
|
||||
position_before_rarrow(&fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
|
||||
(
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
})
|
||||
} else {
|
||||
(ty.span, Applicability::MaybeIncorrect)
|
||||
};
|
||||
let (ret_span, appl) =
|
||||
snippet_opt(cx, span.with_hi(ty.span.hi())).map_or((ty.span, Applicability::MaybeIncorrect), |fn_source| {
|
||||
position_before_rarrow(&fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
|
||||
(
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
})
|
||||
});
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNUSED_UNIT,
|
||||
|
@ -36,13 +36,13 @@ impl TryConf {
|
||||
/// See (rust-clippy#7172)
|
||||
macro_rules! define_Conf {
|
||||
($(
|
||||
#[doc = $doc:literal]
|
||||
$(#[doc = $doc:literal])+
|
||||
$(#[conf_deprecated($dep:literal)])?
|
||||
($name:ident: $ty:ty = $default:expr),
|
||||
)*) => {
|
||||
/// Clippy lint configuration
|
||||
pub struct Conf {
|
||||
$(#[doc = $doc] pub $name: $ty,)*
|
||||
$($(#[doc = $doc])+ pub $name: $ty,)*
|
||||
}
|
||||
|
||||
mod defaults {
|
||||
@ -119,7 +119,7 @@ macro_rules! define_Conf {
|
||||
stringify!($name),
|
||||
stringify!($ty),
|
||||
format!("{:?}", super::defaults::$name()),
|
||||
$doc,
|
||||
concat!($($doc, '\n',)*),
|
||||
deprecation_reason,
|
||||
)
|
||||
},
|
||||
@ -132,18 +132,30 @@ macro_rules! define_Conf {
|
||||
|
||||
// N.B., this macro is parsed by util/lintlib.py
|
||||
define_Conf! {
|
||||
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION. Suppress lints whenever the suggested change would cause breakage for other crates.
|
||||
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION.
|
||||
///
|
||||
/// Suppress lints whenever the suggested change would cause breakage for other crates.
|
||||
(avoid_breaking_exported_api: bool = true),
|
||||
/// Lint: MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports
|
||||
/// Lint: MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE.
|
||||
///
|
||||
/// The minimum rust version that the project supports
|
||||
(msrv: Option<String> = None),
|
||||
/// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
|
||||
/// Lint: BLACKLISTED_NAME.
|
||||
///
|
||||
/// The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
|
||||
(blacklisted_names: Vec<String> = ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
|
||||
/// Lint: COGNITIVE_COMPLEXITY. The maximum cognitive complexity a function can have
|
||||
/// Lint: COGNITIVE_COMPLEXITY.
|
||||
///
|
||||
/// The maximum cognitive complexity a function can have
|
||||
(cognitive_complexity_threshold: u64 = 25),
|
||||
/// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. Use the Cognitive Complexity lint instead.
|
||||
/// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
|
||||
///
|
||||
/// Use the Cognitive Complexity lint instead.
|
||||
#[conf_deprecated("Please use `cognitive-complexity-threshold` instead")]
|
||||
(cyclomatic_complexity_threshold: Option<u64> = None),
|
||||
/// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
|
||||
/// Lint: DOC_MARKDOWN.
|
||||
///
|
||||
/// The list of words this lint should not consider as identifiers needing ticks
|
||||
(doc_valid_idents: Vec<String> = [
|
||||
"KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
|
||||
"DirectX",
|
||||
@ -164,55 +176,109 @@ define_Conf! {
|
||||
"MinGW",
|
||||
"CamelCase",
|
||||
].iter().map(ToString::to_string).collect()),
|
||||
/// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
|
||||
/// Lint: TOO_MANY_ARGUMENTS.
|
||||
///
|
||||
/// The maximum number of argument a function or method can have
|
||||
(too_many_arguments_threshold: u64 = 7),
|
||||
/// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
|
||||
/// Lint: TYPE_COMPLEXITY.
|
||||
///
|
||||
/// The maximum complexity a type can have
|
||||
(type_complexity_threshold: u64 = 250),
|
||||
/// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
|
||||
/// Lint: MANY_SINGLE_CHAR_NAMES.
|
||||
///
|
||||
/// The maximum number of single char bindings a scope may have
|
||||
(single_char_binding_names_threshold: u64 = 4),
|
||||
/// Lint: BOXED_LOCAL, USELESS_VEC. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
|
||||
/// Lint: BOXED_LOCAL, USELESS_VEC.
|
||||
///
|
||||
/// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
|
||||
(too_large_for_stack: u64 = 200),
|
||||
/// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
|
||||
/// Lint: ENUM_VARIANT_NAMES.
|
||||
///
|
||||
/// The minimum number of enum variants for the lints about variant names to trigger
|
||||
(enum_variant_name_threshold: u64 = 3),
|
||||
/// Lint: LARGE_ENUM_VARIANT. The maximum size of a enum's variant to avoid box suggestion
|
||||
/// Lint: LARGE_ENUM_VARIANT.
|
||||
///
|
||||
/// The maximum size of a enum's variant to avoid box suggestion
|
||||
(enum_variant_size_threshold: u64 = 200),
|
||||
/// Lint: VERBOSE_BIT_MASK. The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
|
||||
/// Lint: VERBOSE_BIT_MASK.
|
||||
///
|
||||
/// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
|
||||
(verbose_bit_mask_threshold: u64 = 1),
|
||||
/// Lint: DECIMAL_LITERAL_REPRESENTATION. The lower bound for linting decimal literals
|
||||
/// Lint: DECIMAL_LITERAL_REPRESENTATION.
|
||||
///
|
||||
/// The lower bound for linting decimal literals
|
||||
(literal_representation_threshold: u64 = 16384),
|
||||
/// Lint: TRIVIALLY_COPY_PASS_BY_REF. The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
|
||||
/// Lint: TRIVIALLY_COPY_PASS_BY_REF.
|
||||
///
|
||||
/// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
|
||||
(trivial_copy_size_limit: Option<u64> = None),
|
||||
/// Lint: LARGE_TYPE_PASS_BY_MOVE. The minimum size (in bytes) to consider a type for passing by reference instead of by value.
|
||||
/// Lint: LARGE_TYPE_PASS_BY_MOVE.
|
||||
///
|
||||
/// The minimum size (in bytes) to consider a type for passing by reference instead of by value.
|
||||
(pass_by_value_size_limit: u64 = 256),
|
||||
/// Lint: TOO_MANY_LINES. The maximum number of lines a function or method can have
|
||||
/// Lint: TOO_MANY_LINES.
|
||||
///
|
||||
/// The maximum number of lines a function or method can have
|
||||
(too_many_lines_threshold: u64 = 100),
|
||||
/// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. The maximum allowed size for arrays on the stack
|
||||
/// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS.
|
||||
///
|
||||
/// The maximum allowed size for arrays on the stack
|
||||
(array_size_threshold: u64 = 512_000),
|
||||
/// Lint: VEC_BOX. The size of the boxed type in bytes, where boxing in a `Vec` is allowed
|
||||
/// Lint: VEC_BOX.
|
||||
///
|
||||
/// The size of the boxed type in bytes, where boxing in a `Vec` is allowed
|
||||
(vec_box_size_threshold: u64 = 4096),
|
||||
/// Lint: TYPE_REPETITION_IN_BOUNDS. The maximum number of bounds a trait can have to be linted
|
||||
/// Lint: TYPE_REPETITION_IN_BOUNDS.
|
||||
///
|
||||
/// The maximum number of bounds a trait can have to be linted
|
||||
(max_trait_bounds: u64 = 3),
|
||||
/// Lint: STRUCT_EXCESSIVE_BOOLS. The maximum number of bool fields a struct can have
|
||||
/// Lint: STRUCT_EXCESSIVE_BOOLS.
|
||||
///
|
||||
/// The maximum number of bool fields a struct can have
|
||||
(max_struct_bools: u64 = 3),
|
||||
/// Lint: FN_PARAMS_EXCESSIVE_BOOLS. The maximum number of bool parameters a function can have
|
||||
/// Lint: FN_PARAMS_EXCESSIVE_BOOLS.
|
||||
///
|
||||
/// The maximum number of bool parameters a function can have
|
||||
(max_fn_params_bools: u64 = 3),
|
||||
/// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests).
|
||||
/// Lint: WILDCARD_IMPORTS.
|
||||
///
|
||||
/// Whether to allow certain wildcard imports (prelude, super in tests).
|
||||
(warn_on_all_wildcard_imports: bool = false),
|
||||
/// Lint: DISALLOWED_METHOD. The list of disallowed methods, written as fully qualified paths.
|
||||
/// Lint: DISALLOWED_METHOD.
|
||||
///
|
||||
/// The list of disallowed methods, written as fully qualified paths.
|
||||
(disallowed_methods: Vec<String> = Vec::new()),
|
||||
/// Lint: DISALLOWED_TYPE. The list of disallowed types, written as fully qualified paths.
|
||||
/// Lint: DISALLOWED_TYPE.
|
||||
///
|
||||
/// The list of disallowed types, written as fully qualified paths.
|
||||
(disallowed_types: Vec<String> = Vec::new()),
|
||||
/// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators.
|
||||
/// Lint: UNREADABLE_LITERAL.
|
||||
///
|
||||
/// Should the fraction of a decimal be linted to include separators.
|
||||
(unreadable_literal_lint_fractions: bool = true),
|
||||
/// Lint: UPPER_CASE_ACRONYMS. Enables verbose mode. Triggers if there is more than one uppercase char next to each other
|
||||
/// Lint: UPPER_CASE_ACRONYMS.
|
||||
///
|
||||
/// Enables verbose mode. Triggers if there is more than one uppercase char next to each other
|
||||
(upper_case_acronyms_aggressive: bool = false),
|
||||
/// Lint: _CARGO_COMMON_METADATA. For internal testing only, ignores the current `publish` settings in the Cargo manifest.
|
||||
/// Lint: _CARGO_COMMON_METADATA.
|
||||
///
|
||||
/// For internal testing only, ignores the current `publish` settings in the Cargo manifest.
|
||||
(cargo_ignore_publish: bool = false),
|
||||
/// Lint: NONSTANDARD_MACRO_BRACES. Enforce the named macros always use the braces specified. <br> A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro is could be used with a full path two `MacroMatcher`s have to be added one with the full path `crate_name::macro_name` and one with just the macro name.
|
||||
/// Lint: NONSTANDARD_MACRO_BRACES.
|
||||
///
|
||||
/// Enforce the named macros always use the braces specified.
|
||||
///
|
||||
/// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
|
||||
/// is could be used with a full path two `MacroMatcher`s have to be added one with the full path
|
||||
/// `crate_name::macro_name` and one with just the macro name.
|
||||
(standard_macro_braces: Vec<crate::nonstandard_macro_braces::MacroMatcher> = Vec::new()),
|
||||
/// Lint: MISSING_ENFORCED_IMPORT_RENAMES. The list of imports to always rename, a fully qualified path followed by the rename.
|
||||
/// Lint: MISSING_ENFORCED_IMPORT_RENAMES.
|
||||
///
|
||||
/// The list of imports to always rename, a fully qualified path followed by the rename.
|
||||
(enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()),
|
||||
/// Lint: RESTRICTED_SCRIPTS. The list of unicode scripts allowed to be used in the scope.
|
||||
/// Lint: RESTRICTED_SCRIPTS.
|
||||
///
|
||||
/// The list of unicode scripts allowed to be used in the scope.
|
||||
(allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,7 @@ This lint has the following configuration variables:
|
||||
/// `default`
|
||||
macro_rules! CONFIGURATION_VALUE_TEMPLATE {
|
||||
() => {
|
||||
"* {name}: {ty}: {doc} (defaults to `{default}`)\n"
|
||||
"* {name}: `{ty}`: {doc} (defaults to `{default}`)\n"
|
||||
};
|
||||
}
|
||||
|
||||
@ -344,11 +344,16 @@ fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
|
||||
if let Some(split_pos) = doc_comment.find('.');
|
||||
then {
|
||||
let mut doc_comment = doc_comment.to_string();
|
||||
let documentation = doc_comment.split_off(split_pos);
|
||||
let mut documentation = doc_comment.split_off(split_pos);
|
||||
|
||||
// Extract lints
|
||||
doc_comment.make_ascii_lowercase();
|
||||
let lints: Vec<String> = doc_comment.split_off(DOC_START.len()).split(", ").map(str::to_string).collect();
|
||||
|
||||
// Format documentation correctly
|
||||
// split off leading `.` from lint name list and indent for correct formatting
|
||||
documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n ");
|
||||
|
||||
Some((lints, documentation))
|
||||
} else {
|
||||
None
|
||||
|
@ -65,7 +65,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// ```text
|
||||
/// error: constant division of 0.0 with 0.0 will always result in NaN
|
||||
/// --> $DIR/zero_div_zero.rs:6:25
|
||||
/// |
|
||||
@ -103,7 +103,7 @@ pub fn span_lint_and_help<'a, T: LintContext>(
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// ```text
|
||||
/// error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
|
||||
/// --> $DIR/drop_forget_ref.rs:10:5
|
||||
/// |
|
||||
@ -189,7 +189,7 @@ pub fn span_lint_hir_and_then(
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// ```text
|
||||
/// error: This `.fold` can be more succinctly expressed as `.any`
|
||||
/// --> $DIR/methods.rs:390:13
|
||||
/// |
|
||||
|
@ -195,8 +195,8 @@ pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<Ve
|
||||
/// - `assert!`, `assert_eq!` and `assert_ne!`
|
||||
/// - `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!`
|
||||
/// For example:
|
||||
/// `assert!(expr)` will return Some([expr])
|
||||
/// `debug_assert_eq!(a, b)` will return Some([a, b])
|
||||
/// `assert!(expr)` will return `Some([expr])`
|
||||
/// `debug_assert_eq!(a, b)` will return `Some([a, b])`
|
||||
pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx Expr<'tcx>>> {
|
||||
/// Try to match the AST for a pattern that contains a match, for example when two args are
|
||||
/// compared
|
||||
@ -283,7 +283,7 @@ pub struct FormatArgsExpn<'tcx> {
|
||||
|
||||
/// String literal expressions which represent the format string split by "{}"
|
||||
pub format_string_parts: &'tcx [Expr<'tcx>],
|
||||
/// Symbols corresponding to [`format_string_parts`]
|
||||
/// Symbols corresponding to [`Self::format_string_parts`]
|
||||
pub format_string_symbols: Vec<Symbol>,
|
||||
/// Expressions like `ArgumentV1::new(arg0, Debug::fmt)`
|
||||
pub args: &'tcx [Expr<'tcx>],
|
||||
|
@ -326,6 +326,25 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol)
|
||||
.map_or(false, |did| is_diag_trait_item(cx, did, diag_item))
|
||||
}
|
||||
|
||||
/// Checks if the given expression is a path referring an item on the trait
|
||||
/// that is marked with the given diagnostic item.
|
||||
///
|
||||
/// For checking method call expressions instead of path expressions, use
|
||||
/// [`is_trait_method`].
|
||||
///
|
||||
/// For example, this can be used to find if an expression like `u64::default`
|
||||
/// refers to an item of the trait `Default`, which is associated with the
|
||||
/// `diag_item` of `sym::Default`.
|
||||
pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
|
||||
if let hir::ExprKind::Path(ref qpath) = expr.kind {
|
||||
cx.qpath_res(qpath, expr.hir_id)
|
||||
.opt_def_id()
|
||||
.map_or(false, |def_id| is_diag_trait_item(cx, def_id, diag_item))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
|
||||
match *path {
|
||||
QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
|
||||
@ -558,6 +577,54 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio
|
||||
None
|
||||
}
|
||||
|
||||
/// This method will return tuple of projection stack and root of the expression,
|
||||
/// used in `can_mut_borrow_both`.
|
||||
///
|
||||
/// For example, if `e` represents the `v[0].a.b[x]`
|
||||
/// this method will return a tuple, composed of a `Vec`
|
||||
/// containing the `Expr`s for `v[0], v[0].a, v[0].a.b, v[0].a.b[x]`
|
||||
/// and a `Expr` for root of them, `v`
|
||||
fn projection_stack<'a, 'hir>(mut e: &'a Expr<'hir>) -> (Vec<&'a Expr<'hir>>, &'a Expr<'hir>) {
|
||||
let mut result = vec![];
|
||||
let root = loop {
|
||||
match e.kind {
|
||||
ExprKind::Index(ep, _) | ExprKind::Field(ep, _) => {
|
||||
result.push(e);
|
||||
e = ep;
|
||||
},
|
||||
_ => break e,
|
||||
};
|
||||
};
|
||||
result.reverse();
|
||||
(result, root)
|
||||
}
|
||||
|
||||
/// Checks if two expressions can be mutably borrowed simultaneously
|
||||
/// and they aren't dependent on borrowing same thing twice
|
||||
pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) -> bool {
|
||||
let (s1, r1) = projection_stack(e1);
|
||||
let (s2, r2) = projection_stack(e2);
|
||||
if !eq_expr_value(cx, r1, r2) {
|
||||
return true;
|
||||
}
|
||||
for (x1, x2) in s1.iter().zip(s2.iter()) {
|
||||
match (&x1.kind, &x2.kind) {
|
||||
(ExprKind::Field(_, i1), ExprKind::Field(_, i2)) => {
|
||||
if i1 != i2 {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
(ExprKind::Index(_, i1), ExprKind::Index(_, i2)) => {
|
||||
if !eq_expr_value(cx, i1, i2) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Checks if the top level expression can be moved into a closure as is.
|
||||
pub fn can_move_expr_to_closure_no_visit(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, jump_targets: &[HirId]) -> bool {
|
||||
match expr.kind {
|
||||
|
@ -168,7 +168,7 @@ pub fn snippet<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<
|
||||
snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from)
|
||||
}
|
||||
|
||||
/// Same as `snippet`, but it adapts the applicability level by following rules:
|
||||
/// Same as [`snippet`], but it adapts the applicability level by following rules:
|
||||
///
|
||||
/// - Applicability level `Unspecified` will never be changed.
|
||||
/// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`.
|
||||
|
@ -114,7 +114,7 @@ pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<
|
||||
|
||||
/// Checks whether a type implements a trait.
|
||||
/// The function returns false in case the type contains an inference variable.
|
||||
/// See also `get_trait_def_id`.
|
||||
/// See also [`get_trait_def_id`](super::get_trait_def_id).
|
||||
pub fn implements_trait<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
|
@ -166,8 +166,8 @@ rustup component add clippy
|
||||
```
|
||||
|
||||
> **DO NOT** install using `cargo install --path . --force` since this will overwrite rustup
|
||||
[proxies](https://rust-lang.github.io/rustup/concepts/proxies.html). That is, `~/.cargo/bin/cargo-clippy` and
|
||||
`~/.cargo/bin/clippy-driver` should be hard or soft links to `~/.cargo/bin/rustup`. You can repair these by running
|
||||
`rustup update`.
|
||||
> [proxies](https://rust-lang.github.io/rustup/concepts/proxies.html). That is, `~/.cargo/bin/cargo-clippy` and
|
||||
> `~/.cargo/bin/clippy-driver` should be hard or soft links to `~/.cargo/bin/rustup`. You can repair these by running
|
||||
> `rustup update`.
|
||||
|
||||
[glossary]: https://rustc-dev-guide.rust-lang.org/appendix/glossary.html
|
||||
|
@ -1,3 +1,5 @@
|
||||
// edition:2018
|
||||
|
||||
#![warn(clippy::too_many_lines)]
|
||||
|
||||
// This function should be considered one line.
|
||||
@ -20,6 +22,20 @@ fn too_many_lines() {
|
||||
println!("This is bad.");
|
||||
}
|
||||
|
||||
// This should only fail once (#7517).
|
||||
async fn async_too_many_lines() {
|
||||
println!("This is bad.");
|
||||
println!("This is bad.");
|
||||
}
|
||||
|
||||
// This should fail only once, without failing on the closure.
|
||||
fn closure_too_many_lines() {
|
||||
let _ = {
|
||||
println!("This is bad.");
|
||||
println!("This is bad.");
|
||||
};
|
||||
}
|
||||
|
||||
// This should be considered one line.
|
||||
#[rustfmt::skip]
|
||||
fn comment_starts_after_code() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: this function has too many lines (2/1)
|
||||
--> $DIR/test.rs:18:1
|
||||
--> $DIR/test.rs:20:1
|
||||
|
|
||||
LL | / fn too_many_lines() {
|
||||
LL | | println!("This is bad.");
|
||||
@ -9,8 +9,28 @@ LL | | }
|
||||
|
|
||||
= note: `-D clippy::too-many-lines` implied by `-D warnings`
|
||||
|
||||
error: this function has too many lines (4/1)
|
||||
--> $DIR/test.rs:26:1
|
||||
|
|
||||
LL | / async fn async_too_many_lines() {
|
||||
LL | | println!("This is bad.");
|
||||
LL | | println!("This is bad.");
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: this function has too many lines (4/1)
|
||||
--> $DIR/test.rs:32:1
|
||||
|
|
||||
LL | / fn closure_too_many_lines() {
|
||||
LL | | let _ = {
|
||||
LL | | println!("This is bad.");
|
||||
LL | | println!("This is bad.");
|
||||
LL | | };
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: this function has too many lines (2/1)
|
||||
--> $DIR/test.rs:38:1
|
||||
--> $DIR/test.rs:54:1
|
||||
|
|
||||
LL | / fn comment_before_code() {
|
||||
LL | | let _ = "test";
|
||||
@ -19,5 +39,5 @@ LL | | the code but this line should still count. */ let _ = 5;
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
@ -32,13 +32,19 @@ macro_rules! type_pos {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! printlnfoo {
|
||||
($thing:expr) => {
|
||||
println!("{}", $thing)
|
||||
};
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn main() {
|
||||
let _ = vec! {1, 2, 3};
|
||||
let _ = format!["ugh {} stop being such a good compiler", "hello"];
|
||||
let _ = quote!(let x = 1;);
|
||||
let _ = quote::quote!(match match match);
|
||||
let _ = test!();
|
||||
let _ = test!(); // trigger when macro def is inside our own crate
|
||||
let _ = vec![1,2,3];
|
||||
|
||||
let _ = quote::quote! {true || false};
|
||||
@ -49,4 +55,6 @@ fn main() {
|
||||
let _: type_pos!(usize) = vec![];
|
||||
|
||||
eprint!("test if user config overrides defaults");
|
||||
|
||||
printlnfoo!["test if printlnfoo is triggered by println"];
|
||||
}
|
||||
|
@ -1,48 +1,48 @@
|
||||
error: use of irregular braces for `vec!` macro
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:37:13
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:43:13
|
||||
|
|
||||
LL | let _ = vec! {1, 2, 3};
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::nonstandard-macro-braces` implied by `-D warnings`
|
||||
help: consider writing `vec![1, 2, 3]`
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:37:13
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:43:13
|
||||
|
|
||||
LL | let _ = vec! {1, 2, 3};
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: use of irregular braces for `format!` macro
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:38:13
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:44:13
|
||||
|
|
||||
LL | let _ = format!["ugh {} stop being such a good compiler", "hello"];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider writing `format!("ugh () stop being such a good compiler", "hello")`
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:38:13
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:44:13
|
||||
|
|
||||
LL | let _ = format!["ugh {} stop being such a good compiler", "hello"];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of irregular braces for `quote!` macro
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:39:13
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:45:13
|
||||
|
|
||||
LL | let _ = quote!(let x = 1;);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider writing `quote! {let x = 1;}`
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:39:13
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:45:13
|
||||
|
|
||||
LL | let _ = quote!(let x = 1;);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of irregular braces for `quote::quote!` macro
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:40:13
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:46:13
|
||||
|
|
||||
LL | let _ = quote::quote!(match match match);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider writing `quote::quote! {match match match}`
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:40:13
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:46:13
|
||||
|
|
||||
LL | let _ = quote::quote!(match match match);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -53,7 +53,7 @@ error: use of irregular braces for `vec!` macro
|
||||
LL | vec!{0, 0, 0}
|
||||
| ^^^^^^^^^^^^^
|
||||
...
|
||||
LL | let _ = test!();
|
||||
LL | let _ = test!(); // trigger when macro def is inside our own crate
|
||||
| ------- in this macro invocation
|
||||
|
|
||||
help: consider writing `vec![0, 0, 0]`
|
||||
@ -62,30 +62,30 @@ help: consider writing `vec![0, 0, 0]`
|
||||
LL | vec!{0, 0, 0}
|
||||
| ^^^^^^^^^^^^^
|
||||
...
|
||||
LL | let _ = test!();
|
||||
LL | let _ = test!(); // trigger when macro def is inside our own crate
|
||||
| ------- in this macro invocation
|
||||
= note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: use of irregular braces for `type_pos!` macro
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:49:12
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:55:12
|
||||
|
|
||||
LL | let _: type_pos!(usize) = vec![];
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider writing `type_pos![usize]`
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:49:12
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:55:12
|
||||
|
|
||||
LL | let _: type_pos!(usize) = vec![];
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of irregular braces for `eprint!` macro
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:51:5
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:57:5
|
||||
|
|
||||
LL | eprint!("test if user config overrides defaults");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider writing `eprint!["test if user config overrides defaults"];`
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:51:5
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:57:5
|
||||
|
|
||||
LL | eprint!("test if user config overrides defaults");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -41,7 +41,12 @@ fn main() {
|
||||
|
||||
let mut heap = BinaryHeap::from(vec![1, 3]);
|
||||
let mut heap2 = BinaryHeap::from(vec![]);
|
||||
heap2.extend(heap.drain())
|
||||
heap2.extend(heap.drain());
|
||||
|
||||
let mut x = vec![0, 1, 2, 3, 5];
|
||||
let ref_x = &mut x;
|
||||
let mut y = Vec::new();
|
||||
y.append(ref_x);
|
||||
}
|
||||
|
||||
fn return_vector() -> Vec<u8> {
|
||||
|
@ -41,7 +41,12 @@ fn main() {
|
||||
|
||||
let mut heap = BinaryHeap::from(vec![1, 3]);
|
||||
let mut heap2 = BinaryHeap::from(vec![]);
|
||||
heap2.extend(heap.drain())
|
||||
heap2.extend(heap.drain());
|
||||
|
||||
let mut x = vec![0, 1, 2, 3, 5];
|
||||
let ref_x = &mut x;
|
||||
let mut y = Vec::new();
|
||||
y.extend(ref_x.drain(..));
|
||||
}
|
||||
|
||||
fn return_vector() -> Vec<u8> {
|
||||
|
@ -18,5 +18,11 @@ error: use of `extend` instead of `append` for adding the full range of a second
|
||||
LL | vec11.extend(return_vector().drain(..));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec11.append(&mut return_vector())`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: use of `extend` instead of `append` for adding the full range of a second vector
|
||||
--> $DIR/extend_with_drain.rs:49:5
|
||||
|
|
||||
LL | y.extend(ref_x.drain(..));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `y.append(ref_x)`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
@ -89,7 +89,7 @@ gen!(fn bar);
|
||||
// and should not cause an ICE
|
||||
// See #2707
|
||||
#[macro_use]
|
||||
#[path = "../auxiliary/test_macro.rs"]
|
||||
#[path = "auxiliary/test_macro.rs"]
|
||||
pub mod test_macro;
|
||||
__implicit_hasher_test_macro!(impl<K, V> for HashMap<K, V> where V: test_macro::A);
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#![allow(clippy::missing_docs_in_private_items)]
|
||||
#![allow(clippy::map_identity)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
#![feature(result_flattening)]
|
||||
|
||||
fn main() {
|
||||
// mapping to Option on Iterator
|
||||
@ -23,4 +24,7 @@ fn main() {
|
||||
|
||||
// mapping to Option on Option
|
||||
let _: Option<_> = (Some(Some(1))).and_then(|x| x);
|
||||
|
||||
// mapping to Result on Result
|
||||
let _: Result<_, &str> = (Ok(Ok(1))).and_then(|x| x);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#![allow(clippy::missing_docs_in_private_items)]
|
||||
#![allow(clippy::map_identity)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
#![feature(result_flattening)]
|
||||
|
||||
fn main() {
|
||||
// mapping to Option on Iterator
|
||||
@ -23,4 +24,7 @@ fn main() {
|
||||
|
||||
// mapping to Option on Option
|
||||
let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
|
||||
|
||||
// mapping to Result on Result
|
||||
let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:16:46
|
||||
--> $DIR/map_flatten.rs:17:46
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)`
|
||||
@ -7,34 +7,40 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll
|
||||
= note: `-D clippy::map-flatten` implied by `-D warnings`
|
||||
|
||||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:17:46
|
||||
--> $DIR/map_flatten.rs:18:46
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)`
|
||||
|
||||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:18:46
|
||||
--> $DIR/map_flatten.rs:19:46
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)`
|
||||
|
||||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:19:46
|
||||
--> $DIR/map_flatten.rs:20:46
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))`
|
||||
|
||||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:22:46
|
||||
--> $DIR/map_flatten.rs:23:46
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `.flat_map(|x| 0..x)`
|
||||
|
||||
error: called `map(..).flatten()` on an `Option`
|
||||
--> $DIR/map_flatten.rs:25:39
|
||||
--> $DIR/map_flatten.rs:26:39
|
||||
|
|
||||
LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: called `map(..).flatten()` on an `Result`
|
||||
--> $DIR/map_flatten.rs:29:41
|
||||
|
|
||||
LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)`
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
@ -75,6 +75,11 @@ LL | | _ => return,
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
help: if you need the first element of the iterator, try writing
|
||||
|
|
||||
LL | if let Some(x) = (0..10).next() {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: this loop never actually loops
|
||||
--> $DIR/never_loop.rs:157:5
|
||||
|
@ -108,6 +108,12 @@ error: statement with no effect
|
||||
LL | 5..6;
|
||||
| ^^^^^
|
||||
|
||||
error: statement with no effect
|
||||
--> $DIR/no_effect.rs:83:5
|
||||
|
|
||||
LL | 5..=6;
|
||||
| ^^^^^^
|
||||
|
||||
error: statement with no effect
|
||||
--> $DIR/no_effect.rs:84:5
|
||||
|
|
||||
@ -150,5 +156,5 @@ error: statement with no effect
|
||||
LL | FooString { s: s };
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 25 previous errors
|
||||
error: aborting due to 26 previous errors
|
||||
|
||||
|
@ -18,6 +18,19 @@ fn or_fun_call() {
|
||||
}
|
||||
}
|
||||
|
||||
struct FakeDefault;
|
||||
impl FakeDefault {
|
||||
fn default() -> Self {
|
||||
FakeDefault
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FakeDefault {
|
||||
fn default() -> Self {
|
||||
FakeDefault
|
||||
}
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
A(i32),
|
||||
}
|
||||
@ -53,6 +66,12 @@ fn or_fun_call() {
|
||||
let with_default_type = Some(1);
|
||||
with_default_type.unwrap_or_default();
|
||||
|
||||
let self_default = None::<FakeDefault>;
|
||||
self_default.unwrap_or_else(<FakeDefault>::default);
|
||||
|
||||
let real_default = None::<FakeDefault>;
|
||||
real_default.unwrap_or_default();
|
||||
|
||||
let with_vec = Some(vec![1]);
|
||||
with_vec.unwrap_or_default();
|
||||
|
||||
|
@ -18,6 +18,19 @@ fn or_fun_call() {
|
||||
}
|
||||
}
|
||||
|
||||
struct FakeDefault;
|
||||
impl FakeDefault {
|
||||
fn default() -> Self {
|
||||
FakeDefault
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FakeDefault {
|
||||
fn default() -> Self {
|
||||
FakeDefault
|
||||
}
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
A(i32),
|
||||
}
|
||||
@ -53,6 +66,12 @@ fn or_fun_call() {
|
||||
let with_default_type = Some(1);
|
||||
with_default_type.unwrap_or(u64::default());
|
||||
|
||||
let self_default = None::<FakeDefault>;
|
||||
self_default.unwrap_or(<FakeDefault>::default());
|
||||
|
||||
let real_default = None::<FakeDefault>;
|
||||
real_default.unwrap_or(<FakeDefault as Default>::default());
|
||||
|
||||
let with_vec = Some(vec![1]);
|
||||
with_vec.unwrap_or(vec![]);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:33:19
|
||||
--> $DIR/or_fun_call.rs:46:19
|
||||
|
|
||||
LL | with_const_fn.unwrap_or(Duration::from_secs(5));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Duration::from_secs(5))`
|
||||
@ -7,130 +7,142 @@ LL | with_const_fn.unwrap_or(Duration::from_secs(5));
|
||||
= note: `-D clippy::or-fun-call` implied by `-D warnings`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:36:22
|
||||
--> $DIR/or_fun_call.rs:49:22
|
||||
|
|
||||
LL | with_constructor.unwrap_or(make());
|
||||
| ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)`
|
||||
|
||||
error: use of `unwrap_or` followed by a call to `new`
|
||||
--> $DIR/or_fun_call.rs:39:5
|
||||
--> $DIR/or_fun_call.rs:52:5
|
||||
|
|
||||
LL | with_new.unwrap_or(Vec::new());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_new.unwrap_or_default()`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:42:21
|
||||
--> $DIR/or_fun_call.rs:55:21
|
||||
|
|
||||
LL | with_const_args.unwrap_or(Vec::with_capacity(12));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:45:14
|
||||
--> $DIR/or_fun_call.rs:58:14
|
||||
|
|
||||
LL | with_err.unwrap_or(make());
|
||||
| ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:48:19
|
||||
--> $DIR/or_fun_call.rs:61:19
|
||||
|
|
||||
LL | with_err_args.unwrap_or(Vec::with_capacity(12));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))`
|
||||
|
||||
error: use of `unwrap_or` followed by a call to `default`
|
||||
--> $DIR/or_fun_call.rs:51:5
|
||||
--> $DIR/or_fun_call.rs:64:5
|
||||
|
|
||||
LL | with_default_trait.unwrap_or(Default::default());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_trait.unwrap_or_default()`
|
||||
|
||||
error: use of `unwrap_or` followed by a call to `default`
|
||||
--> $DIR/or_fun_call.rs:54:5
|
||||
--> $DIR/or_fun_call.rs:67:5
|
||||
|
|
||||
LL | with_default_type.unwrap_or(u64::default());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_type.unwrap_or_default()`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:70:18
|
||||
|
|
||||
LL | self_default.unwrap_or(<FakeDefault>::default());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(<FakeDefault>::default)`
|
||||
|
||||
error: use of `unwrap_or` followed by a call to `default`
|
||||
--> $DIR/or_fun_call.rs:73:5
|
||||
|
|
||||
LL | real_default.unwrap_or(<FakeDefault as Default>::default());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `real_default.unwrap_or_default()`
|
||||
|
||||
error: use of `unwrap_or` followed by a call to `new`
|
||||
--> $DIR/or_fun_call.rs:57:5
|
||||
--> $DIR/or_fun_call.rs:76:5
|
||||
|
|
||||
LL | with_vec.unwrap_or(vec![]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_vec.unwrap_or_default()`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:60:21
|
||||
--> $DIR/or_fun_call.rs:79:21
|
||||
|
|
||||
LL | without_default.unwrap_or(Foo::new());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
|
||||
|
||||
error: use of `or_insert` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:63:19
|
||||
--> $DIR/or_fun_call.rs:82:19
|
||||
|
|
||||
LL | map.entry(42).or_insert(String::new());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
|
||||
|
||||
error: use of `or_insert` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:66:23
|
||||
--> $DIR/or_fun_call.rs:85:23
|
||||
|
|
||||
LL | map_vec.entry(42).or_insert(vec![]);
|
||||
| ^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(Vec::new)`
|
||||
|
||||
error: use of `or_insert` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:69:21
|
||||
--> $DIR/or_fun_call.rs:88:21
|
||||
|
|
||||
LL | btree.entry(42).or_insert(String::new());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
|
||||
|
||||
error: use of `or_insert` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:72:25
|
||||
--> $DIR/or_fun_call.rs:91:25
|
||||
|
|
||||
LL | btree_vec.entry(42).or_insert(vec![]);
|
||||
| ^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(Vec::new)`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:75:21
|
||||
--> $DIR/or_fun_call.rs:94:21
|
||||
|
|
||||
LL | let _ = stringy.unwrap_or("".to_owned());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:83:21
|
||||
--> $DIR/or_fun_call.rs:102:21
|
||||
|
|
||||
LL | let _ = Some(1).unwrap_or(map[&1]);
|
||||
| ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:85:21
|
||||
--> $DIR/or_fun_call.rs:104:21
|
||||
|
|
||||
LL | let _ = Some(1).unwrap_or(map[&1]);
|
||||
| ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])`
|
||||
|
||||
error: use of `or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:109:35
|
||||
--> $DIR/or_fun_call.rs:128:35
|
||||
|
|
||||
LL | let _ = Some("a".to_string()).or(Some("b".to_string()));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))`
|
||||
|
||||
error: use of `or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:113:10
|
||||
--> $DIR/or_fun_call.rs:132:10
|
||||
|
|
||||
LL | .or(Some(Bar(b, Duration::from_secs(2))));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:141:14
|
||||
--> $DIR/or_fun_call.rs:160:14
|
||||
|
|
||||
LL | None.unwrap_or(s.as_mut_vec());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| s.as_mut_vec())`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:146:14
|
||||
--> $DIR/or_fun_call.rs:165:14
|
||||
|
|
||||
LL | None.unwrap_or(unsafe { s.as_mut_vec() });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })`
|
||||
|
||||
error: use of `unwrap_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:148:14
|
||||
--> $DIR/or_fun_call.rs:167:14
|
||||
|
|
||||
LL | None.unwrap_or( unsafe { s.as_mut_vec() } );
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { s.as_mut_vec() })`
|
||||
|
||||
error: aborting due to 22 previous errors
|
||||
error: aborting due to 24 previous errors
|
||||
|
||||
|
@ -76,6 +76,9 @@ fn main() {
|
||||
// names often used in win32 code (for example WindowProc)
|
||||
let wparam: i32;
|
||||
let lparam: i32;
|
||||
|
||||
let iter: i32;
|
||||
let item: i32;
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
|
@ -72,13 +72,13 @@ LL | let parser: i32;
|
||||
| ^^^^^^
|
||||
|
||||
error: binding's name is too similar to existing binding
|
||||
--> $DIR/similar_names.rs:85:16
|
||||
--> $DIR/similar_names.rs:88:16
|
||||
|
|
||||
LL | bpple: sprang,
|
||||
| ^^^^^^
|
||||
|
|
||||
note: existing binding defined here
|
||||
--> $DIR/similar_names.rs:84:16
|
||||
--> $DIR/similar_names.rs:87:16
|
||||
|
|
||||
LL | apple: spring,
|
||||
| ^^^^^^
|
||||
|
@ -6,6 +6,7 @@
|
||||
clippy::no_effect,
|
||||
clippy::redundant_clone,
|
||||
redundant_semicolons,
|
||||
dead_code,
|
||||
unused_assignments
|
||||
)]
|
||||
|
||||
@ -20,9 +21,7 @@ struct Bar {
|
||||
fn field() {
|
||||
let mut bar = Bar { a: 1, b: 2 };
|
||||
|
||||
let temp = bar.a;
|
||||
bar.a = bar.b;
|
||||
bar.b = temp;
|
||||
std::mem::swap(&mut bar.a, &mut bar.b);
|
||||
|
||||
let mut baz = vec![bar.clone(), bar.clone()];
|
||||
let temp = baz[0].a;
|
||||
@ -51,6 +50,7 @@ fn unswappable_slice() {
|
||||
foo[1][0] = temp;
|
||||
|
||||
// swap(foo[0][1], foo[1][0]) would fail
|
||||
// this could use split_at_mut and mem::swap, but that is not much simpler.
|
||||
}
|
||||
|
||||
fn vec() {
|
||||
@ -60,13 +60,54 @@ fn vec() {
|
||||
foo.swap(0, 1);
|
||||
}
|
||||
|
||||
fn xor_swap_locals() {
|
||||
// This is an xor-based swap of local variables.
|
||||
let mut a = 0;
|
||||
let mut b = 1;
|
||||
std::mem::swap(&mut a, &mut b)
|
||||
}
|
||||
|
||||
fn xor_field_swap() {
|
||||
// This is an xor-based swap of fields in a struct.
|
||||
let mut bar = Bar { a: 0, b: 1 };
|
||||
std::mem::swap(&mut bar.a, &mut bar.b)
|
||||
}
|
||||
|
||||
fn xor_slice_swap() {
|
||||
// This is an xor-based swap of a slice
|
||||
let foo = &mut [1, 2];
|
||||
foo.swap(0, 1)
|
||||
}
|
||||
|
||||
fn xor_no_swap() {
|
||||
// This is a sequence of xor-assignment statements that doesn't result in a swap.
|
||||
let mut a = 0;
|
||||
let mut b = 1;
|
||||
let mut c = 2;
|
||||
a ^= b;
|
||||
b ^= c;
|
||||
a ^= c;
|
||||
c ^= a;
|
||||
}
|
||||
|
||||
fn xor_unswappable_slice() {
|
||||
let foo = &mut [vec![1, 2], vec![3, 4]];
|
||||
foo[0][1] ^= foo[1][0];
|
||||
foo[1][0] ^= foo[0][0];
|
||||
foo[0][1] ^= foo[1][0];
|
||||
|
||||
// swap(foo[0][1], foo[1][0]) would fail
|
||||
// this could use split_at_mut and mem::swap, but that is not much simpler.
|
||||
}
|
||||
|
||||
fn distinct_slice() {
|
||||
let foo = &mut [vec![1, 2], vec![3, 4]];
|
||||
let bar = &mut [vec![1, 2], vec![3, 4]];
|
||||
std::mem::swap(&mut foo[0][1], &mut bar[1][0]);
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn main() {
|
||||
field();
|
||||
array();
|
||||
slice();
|
||||
unswappable_slice();
|
||||
vec();
|
||||
|
||||
let mut a = 42;
|
||||
let mut b = 1337;
|
||||
|
@ -6,6 +6,7 @@
|
||||
clippy::no_effect,
|
||||
clippy::redundant_clone,
|
||||
redundant_semicolons,
|
||||
dead_code,
|
||||
unused_assignments
|
||||
)]
|
||||
|
||||
@ -55,6 +56,7 @@ fn unswappable_slice() {
|
||||
foo[1][0] = temp;
|
||||
|
||||
// swap(foo[0][1], foo[1][0]) would fail
|
||||
// this could use split_at_mut and mem::swap, but that is not much simpler.
|
||||
}
|
||||
|
||||
fn vec() {
|
||||
@ -66,13 +68,62 @@ fn vec() {
|
||||
foo.swap(0, 1);
|
||||
}
|
||||
|
||||
fn xor_swap_locals() {
|
||||
// This is an xor-based swap of local variables.
|
||||
let mut a = 0;
|
||||
let mut b = 1;
|
||||
a ^= b;
|
||||
b ^= a;
|
||||
a ^= b;
|
||||
}
|
||||
|
||||
fn xor_field_swap() {
|
||||
// This is an xor-based swap of fields in a struct.
|
||||
let mut bar = Bar { a: 0, b: 1 };
|
||||
bar.a ^= bar.b;
|
||||
bar.b ^= bar.a;
|
||||
bar.a ^= bar.b;
|
||||
}
|
||||
|
||||
fn xor_slice_swap() {
|
||||
// This is an xor-based swap of a slice
|
||||
let foo = &mut [1, 2];
|
||||
foo[0] ^= foo[1];
|
||||
foo[1] ^= foo[0];
|
||||
foo[0] ^= foo[1];
|
||||
}
|
||||
|
||||
fn xor_no_swap() {
|
||||
// This is a sequence of xor-assignment statements that doesn't result in a swap.
|
||||
let mut a = 0;
|
||||
let mut b = 1;
|
||||
let mut c = 2;
|
||||
a ^= b;
|
||||
b ^= c;
|
||||
a ^= c;
|
||||
c ^= a;
|
||||
}
|
||||
|
||||
fn xor_unswappable_slice() {
|
||||
let foo = &mut [vec![1, 2], vec![3, 4]];
|
||||
foo[0][1] ^= foo[1][0];
|
||||
foo[1][0] ^= foo[0][0];
|
||||
foo[0][1] ^= foo[1][0];
|
||||
|
||||
// swap(foo[0][1], foo[1][0]) would fail
|
||||
// this could use split_at_mut and mem::swap, but that is not much simpler.
|
||||
}
|
||||
|
||||
fn distinct_slice() {
|
||||
let foo = &mut [vec![1, 2], vec![3, 4]];
|
||||
let bar = &mut [vec![1, 2], vec![3, 4]];
|
||||
let temp = foo[0][1];
|
||||
foo[0][1] = bar[1][0];
|
||||
bar[1][0] = temp;
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn main() {
|
||||
field();
|
||||
array();
|
||||
slice();
|
||||
unswappable_slice();
|
||||
vec();
|
||||
|
||||
let mut a = 42;
|
||||
let mut b = 1337;
|
||||
|
@ -1,15 +1,16 @@
|
||||
error: this looks like you are swapping elements of `foo` manually
|
||||
--> $DIR/swap.rs:35:5
|
||||
error: this looks like you are swapping `bar.a` and `bar.b` manually
|
||||
--> $DIR/swap.rs:24:5
|
||||
|
|
||||
LL | / let temp = foo[0];
|
||||
LL | | foo[0] = foo[1];
|
||||
LL | | foo[1] = temp;
|
||||
| |_________________^ help: try: `foo.swap(0, 1)`
|
||||
LL | / let temp = bar.a;
|
||||
LL | | bar.a = bar.b;
|
||||
LL | | bar.b = temp;
|
||||
| |________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b)`
|
||||
|
|
||||
= note: `-D clippy::manual-swap` implied by `-D warnings`
|
||||
= note: or maybe you should use `std::mem::replace`?
|
||||
|
||||
error: this looks like you are swapping elements of `foo` manually
|
||||
--> $DIR/swap.rs:44:5
|
||||
--> $DIR/swap.rs:36:5
|
||||
|
|
||||
LL | / let temp = foo[0];
|
||||
LL | | foo[0] = foo[1];
|
||||
@ -17,7 +18,15 @@ LL | | foo[1] = temp;
|
||||
| |_________________^ help: try: `foo.swap(0, 1)`
|
||||
|
||||
error: this looks like you are swapping elements of `foo` manually
|
||||
--> $DIR/swap.rs:62:5
|
||||
--> $DIR/swap.rs:45:5
|
||||
|
|
||||
LL | / let temp = foo[0];
|
||||
LL | | foo[0] = foo[1];
|
||||
LL | | foo[1] = temp;
|
||||
| |_________________^ help: try: `foo.swap(0, 1)`
|
||||
|
||||
error: this looks like you are swapping elements of `foo` manually
|
||||
--> $DIR/swap.rs:64:5
|
||||
|
|
||||
LL | / let temp = foo[0];
|
||||
LL | | foo[0] = foo[1];
|
||||
@ -25,7 +34,41 @@ LL | | foo[1] = temp;
|
||||
| |_________________^ help: try: `foo.swap(0, 1)`
|
||||
|
||||
error: this looks like you are swapping `a` and `b` manually
|
||||
--> $DIR/swap.rs:83:7
|
||||
--> $DIR/swap.rs:75:5
|
||||
|
|
||||
LL | / a ^= b;
|
||||
LL | | b ^= a;
|
||||
LL | | a ^= b;
|
||||
| |___________^ help: try: `std::mem::swap(&mut a, &mut b)`
|
||||
|
||||
error: this looks like you are swapping `bar.a` and `bar.b` manually
|
||||
--> $DIR/swap.rs:83:5
|
||||
|
|
||||
LL | / bar.a ^= bar.b;
|
||||
LL | | bar.b ^= bar.a;
|
||||
LL | | bar.a ^= bar.b;
|
||||
| |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b)`
|
||||
|
||||
error: this looks like you are swapping elements of `foo` manually
|
||||
--> $DIR/swap.rs:91:5
|
||||
|
|
||||
LL | / foo[0] ^= foo[1];
|
||||
LL | | foo[1] ^= foo[0];
|
||||
LL | | foo[0] ^= foo[1];
|
||||
| |_____________________^ help: try: `foo.swap(0, 1)`
|
||||
|
||||
error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually
|
||||
--> $DIR/swap.rs:120:5
|
||||
|
|
||||
LL | / let temp = foo[0][1];
|
||||
LL | | foo[0][1] = bar[1][0];
|
||||
LL | | bar[1][0] = temp;
|
||||
| |____________________^ help: try: `std::mem::swap(&mut foo[0][1], &mut bar[1][0])`
|
||||
|
|
||||
= note: or maybe you should use `std::mem::replace`?
|
||||
|
||||
error: this looks like you are swapping `a` and `b` manually
|
||||
--> $DIR/swap.rs:134:7
|
||||
|
|
||||
LL | ; let t = a;
|
||||
| _______^
|
||||
@ -36,7 +79,7 @@ LL | | b = t;
|
||||
= note: or maybe you should use `std::mem::replace`?
|
||||
|
||||
error: this looks like you are swapping `c.0` and `a` manually
|
||||
--> $DIR/swap.rs:92:7
|
||||
--> $DIR/swap.rs:143:7
|
||||
|
|
||||
LL | ; let t = c.0;
|
||||
| _______^
|
||||
@ -47,7 +90,7 @@ LL | | a = t;
|
||||
= note: or maybe you should use `std::mem::replace`?
|
||||
|
||||
error: this looks like you are trying to swap `a` and `b`
|
||||
--> $DIR/swap.rs:80:5
|
||||
--> $DIR/swap.rs:131:5
|
||||
|
|
||||
LL | / a = b;
|
||||
LL | | b = a;
|
||||
@ -57,7 +100,7 @@ LL | | b = a;
|
||||
= note: or maybe you should use `std::mem::replace`?
|
||||
|
||||
error: this looks like you are trying to swap `c.0` and `a`
|
||||
--> $DIR/swap.rs:89:5
|
||||
--> $DIR/swap.rs:140:5
|
||||
|
|
||||
LL | / c.0 = a;
|
||||
LL | | a = c.0;
|
||||
@ -65,5 +108,5 @@ LL | | a = c.0;
|
||||
|
|
||||
= note: or maybe you should use `std::mem::replace`?
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
#![warn(clippy::temporary_assignment)]
|
||||
#![allow(const_item_mutation)]
|
||||
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: assignment to temporary
|
||||
--> $DIR/temporary_assignment.rs:48:5
|
||||
--> $DIR/temporary_assignment.rs:47:5
|
||||
|
|
||||
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`
|
||||
|
||||
error: assignment to temporary
|
||||
--> $DIR/temporary_assignment.rs:49:5
|
||||
--> $DIR/temporary_assignment.rs:48:5
|
||||
|
|
||||
LL | / MultiStruct {
|
||||
LL | | structure: Struct { field: 0 },
|
||||
@ -17,13 +17,13 @@ LL | | .field = 1;
|
||||
| |______________^
|
||||
|
||||
error: assignment to temporary
|
||||
--> $DIR/temporary_assignment.rs:54:5
|
||||
--> $DIR/temporary_assignment.rs:53:5
|
||||
|
|
||||
LL | ArrayStruct { array: [0] }.array[0] = 1;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: assignment to temporary
|
||||
--> $DIR/temporary_assignment.rs:55:5
|
||||
--> $DIR/temporary_assignment.rs:54:5
|
||||
|
|
||||
LL | (0, 0).0 = 1;
|
||||
| ^^^^^^^^^^^^
|
||||
|
@ -58,6 +58,8 @@ impl Foo {
|
||||
fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
|
||||
|
||||
fn bad2(x: &u32, y: &Foo, z: &Baz) {}
|
||||
|
||||
fn bad_issue7518(self, other: &Self) {}
|
||||
}
|
||||
|
||||
impl AsRef<u32> for Foo {
|
||||
|
@ -65,40 +65,46 @@ LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `Baz`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> $DIR/trivially_copy_pass_by_ref.rs:72:16
|
||||
--> $DIR/trivially_copy_pass_by_ref.rs:62:35
|
||||
|
|
||||
LL | fn bad_issue7518(self, other: &Self) {}
|
||||
| ^^^^^ help: consider passing by value instead: `Self`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> $DIR/trivially_copy_pass_by_ref.rs:74:16
|
||||
|
|
||||
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `u32`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> $DIR/trivially_copy_pass_by_ref.rs:72:25
|
||||
--> $DIR/trivially_copy_pass_by_ref.rs:74:25
|
||||
|
|
||||
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `Foo`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> $DIR/trivially_copy_pass_by_ref.rs:72:34
|
||||
--> $DIR/trivially_copy_pass_by_ref.rs:74:34
|
||||
|
|
||||
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `Baz`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> $DIR/trivially_copy_pass_by_ref.rs:76:34
|
||||
--> $DIR/trivially_copy_pass_by_ref.rs:78:34
|
||||
|
|
||||
LL | fn trait_method(&self, _foo: &Foo);
|
||||
| ^^^^ help: consider passing by value instead: `Foo`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> $DIR/trivially_copy_pass_by_ref.rs:108:21
|
||||
--> $DIR/trivially_copy_pass_by_ref.rs:110:21
|
||||
|
|
||||
LL | fn foo_never(x: &i32) {
|
||||
| ^^^^ help: consider passing by value instead: `i32`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> $DIR/trivially_copy_pass_by_ref.rs:113:15
|
||||
--> $DIR/trivially_copy_pass_by_ref.rs:115:15
|
||||
|
|
||||
LL | fn foo(x: &i32) {
|
||||
| ^^^^ help: consider passing by value instead: `i32`
|
||||
|
||||
error: aborting due to 16 previous errors
|
||||
error: aborting due to 17 previous errors
|
||||
|
||||
|
71
tests/ui/unwrap_or_else_default.fixed
Normal file
71
tests/ui/unwrap_or_else_default.fixed
Normal file
@ -0,0 +1,71 @@
|
||||
// run-rustfix
|
||||
|
||||
#![warn(clippy::unwrap_or_else_default)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint.
|
||||
fn unwrap_or_else_default() {
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn new() -> Foo {
|
||||
Foo
|
||||
}
|
||||
|
||||
// fake default, we should not trigger on this
|
||||
fn default() -> Foo {
|
||||
Foo
|
||||
}
|
||||
}
|
||||
|
||||
struct HasDefaultAndDuplicate;
|
||||
|
||||
impl HasDefaultAndDuplicate {
|
||||
fn default() -> Self {
|
||||
HasDefaultAndDuplicate
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for HasDefaultAndDuplicate {
|
||||
fn default() -> Self {
|
||||
HasDefaultAndDuplicate
|
||||
}
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
A(),
|
||||
}
|
||||
|
||||
fn make<T, V>(_: V) -> T {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
let with_enum = Some(Enum::A());
|
||||
with_enum.unwrap_or_else(Enum::A);
|
||||
|
||||
let with_new = Some(vec![1]);
|
||||
with_new.unwrap_or_else(Vec::new);
|
||||
|
||||
let with_err: Result<_, ()> = Ok(vec![1]);
|
||||
with_err.unwrap_or_else(make);
|
||||
|
||||
// should not be changed
|
||||
let with_fake_default = None::<Foo>;
|
||||
with_fake_default.unwrap_or_else(Foo::default);
|
||||
|
||||
// should not be changed
|
||||
let with_fake_default2 = None::<HasDefaultAndDuplicate>;
|
||||
with_fake_default2.unwrap_or_else(<HasDefaultAndDuplicate>::default);
|
||||
|
||||
let with_real_default = None::<HasDefaultAndDuplicate>;
|
||||
with_real_default.unwrap_or_default();
|
||||
|
||||
let with_default_trait = Some(1);
|
||||
with_default_trait.unwrap_or_default();
|
||||
|
||||
let with_default_type = Some(1);
|
||||
with_default_type.unwrap_or_default();
|
||||
}
|
||||
|
||||
fn main() {}
|
71
tests/ui/unwrap_or_else_default.rs
Normal file
71
tests/ui/unwrap_or_else_default.rs
Normal file
@ -0,0 +1,71 @@
|
||||
// run-rustfix
|
||||
|
||||
#![warn(clippy::unwrap_or_else_default)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
|
||||
/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint.
|
||||
fn unwrap_or_else_default() {
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn new() -> Foo {
|
||||
Foo
|
||||
}
|
||||
|
||||
// fake default, we should not trigger on this
|
||||
fn default() -> Foo {
|
||||
Foo
|
||||
}
|
||||
}
|
||||
|
||||
struct HasDefaultAndDuplicate;
|
||||
|
||||
impl HasDefaultAndDuplicate {
|
||||
fn default() -> Self {
|
||||
HasDefaultAndDuplicate
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for HasDefaultAndDuplicate {
|
||||
fn default() -> Self {
|
||||
HasDefaultAndDuplicate
|
||||
}
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
A(),
|
||||
}
|
||||
|
||||
fn make<T, V>(_: V) -> T {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
let with_enum = Some(Enum::A());
|
||||
with_enum.unwrap_or_else(Enum::A);
|
||||
|
||||
let with_new = Some(vec![1]);
|
||||
with_new.unwrap_or_else(Vec::new);
|
||||
|
||||
let with_err: Result<_, ()> = Ok(vec![1]);
|
||||
with_err.unwrap_or_else(make);
|
||||
|
||||
// should not be changed
|
||||
let with_fake_default = None::<Foo>;
|
||||
with_fake_default.unwrap_or_else(Foo::default);
|
||||
|
||||
// should not be changed
|
||||
let with_fake_default2 = None::<HasDefaultAndDuplicate>;
|
||||
with_fake_default2.unwrap_or_else(<HasDefaultAndDuplicate>::default);
|
||||
|
||||
let with_real_default = None::<HasDefaultAndDuplicate>;
|
||||
with_real_default.unwrap_or_else(<HasDefaultAndDuplicate as Default>::default);
|
||||
|
||||
let with_default_trait = Some(1);
|
||||
with_default_trait.unwrap_or_else(Default::default);
|
||||
|
||||
let with_default_type = Some(1);
|
||||
with_default_type.unwrap_or_else(u64::default);
|
||||
}
|
||||
|
||||
fn main() {}
|
22
tests/ui/unwrap_or_else_default.stderr
Normal file
22
tests/ui/unwrap_or_else_default.stderr
Normal file
@ -0,0 +1,22 @@
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:62:5
|
||||
|
|
||||
LL | with_real_default.unwrap_or_else(<HasDefaultAndDuplicate as Default>::default);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_real_default.unwrap_or_default()`
|
||||
|
|
||||
= note: `-D clippy::unwrap-or-else-default` implied by `-D warnings`
|
||||
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:65:5
|
||||
|
|
||||
LL | with_default_trait.unwrap_or_else(Default::default);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_trait.unwrap_or_default()`
|
||||
|
||||
error: use of `.unwrap_or_else(..)` to construct default value
|
||||
--> $DIR/unwrap_or_else_default.rs:68:5
|
||||
|
|
||||
LL | with_default_type.unwrap_or_else(u64::default);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
@ -334,6 +334,38 @@ fn issue7249() {
|
||||
x();
|
||||
}
|
||||
|
||||
fn issue7510() {
|
||||
let mut it = 0..10;
|
||||
let it = &mut it;
|
||||
// Needs to reborrow `it` as the binding isn't mutable
|
||||
for x in &mut *it {
|
||||
if x % 2 == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
println!("{}", it.next().unwrap());
|
||||
|
||||
struct S<T>(T);
|
||||
let mut it = 0..10;
|
||||
let it = S(&mut it);
|
||||
// Needs to reborrow `it.0` as the binding isn't mutable
|
||||
for x in &mut *it.0 {
|
||||
if x % 2 == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
println!("{}", it.0.next().unwrap());
|
||||
}
|
||||
|
||||
fn exact_match_with_single_field() {
|
||||
struct S<T>(T);
|
||||
let mut s = S(0..10);
|
||||
// Don't lint. `s.0` is used inside the loop.
|
||||
while let Some(_) = s.0.next() {
|
||||
let _ = &mut s.0;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut it = 0..20;
|
||||
for _ in it {
|
||||
|
@ -334,6 +334,38 @@ fn issue7249() {
|
||||
x();
|
||||
}
|
||||
|
||||
fn issue7510() {
|
||||
let mut it = 0..10;
|
||||
let it = &mut it;
|
||||
// Needs to reborrow `it` as the binding isn't mutable
|
||||
while let Some(x) = it.next() {
|
||||
if x % 2 == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
println!("{}", it.next().unwrap());
|
||||
|
||||
struct S<T>(T);
|
||||
let mut it = 0..10;
|
||||
let it = S(&mut it);
|
||||
// Needs to reborrow `it.0` as the binding isn't mutable
|
||||
while let Some(x) = it.0.next() {
|
||||
if x % 2 == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
println!("{}", it.0.next().unwrap());
|
||||
}
|
||||
|
||||
fn exact_match_with_single_field() {
|
||||
struct S<T>(T);
|
||||
let mut s = S(0..10);
|
||||
// Don't lint. `s.0` is used inside the loop.
|
||||
while let Some(_) = s.0.next() {
|
||||
let _ = &mut s.0;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut it = 0..20;
|
||||
while let Some(..) = it.next() {
|
||||
|
@ -111,10 +111,22 @@ LL | while let Some(x) = it.next() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in &mut it`
|
||||
|
||||
error: this loop could be written as a `for` loop
|
||||
--> $DIR/while_let_on_iterator.rs:339:5
|
||||
--> $DIR/while_let_on_iterator.rs:341:5
|
||||
|
|
||||
LL | while let Some(x) = it.next() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in &mut *it`
|
||||
|
||||
error: this loop could be written as a `for` loop
|
||||
--> $DIR/while_let_on_iterator.rs:352:5
|
||||
|
|
||||
LL | while let Some(x) = it.0.next() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in &mut *it.0`
|
||||
|
||||
error: this loop could be written as a `for` loop
|
||||
--> $DIR/while_let_on_iterator.rs:371:5
|
||||
|
|
||||
LL | while let Some(..) = it.next() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`
|
||||
|
||||
error: aborting due to 19 previous errors
|
||||
error: aborting due to 21 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user