mirror of
https://github.com/rust-lang/rust-clippy
synced 2025-02-16 22:18:40 +00:00
Merge commit '7248d06384c6a90de58c04c1f46be88821278d8b' into sync-from-clippy
This commit is contained in:
parent
0dc24ca376
commit
4d015293d1
111 changed files with 2040 additions and 1674 deletions
|
@ -3800,6 +3800,7 @@ Released 2018-09-13
|
|||
[`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements
|
||||
[`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect
|
||||
[`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count
|
||||
[`iter_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map
|
||||
[`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
|
||||
[`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice
|
||||
[`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator
|
||||
|
|
|
@ -110,23 +110,28 @@ Just make sure to remove the dependencies again before finally making a pull req
|
|||
[IntelliJ_rust_homepage]: https://intellij-rust.github.io/
|
||||
|
||||
### Rust Analyzer
|
||||
As of [#6869][6869], [`rust-analyzer`][ra_homepage] can understand that Clippy uses compiler-internals
|
||||
using `extern crate` when `package.metadata.rust-analyzer.rustc_private` is set to `true` in Clippy's `Cargo.toml.`
|
||||
You will require a `nightly` toolchain with the `rustc-dev` component installed.
|
||||
Make sure that in the `rust-analyzer` configuration, you set
|
||||
For [`rust-analyzer`][ra_homepage] to work correctly make sure that in the `rust-analyzer` configuration you set
|
||||
|
||||
```json
|
||||
{ "rust-analyzer.rustc.source": "discover" }
|
||||
```
|
||||
and
|
||||
```json
|
||||
{ "rust-analyzer.updates.channel": "nightly" }
|
||||
```
|
||||
|
||||
You should be able to see information on things like `Expr` or `EarlyContext` now if you hover them, also
|
||||
a lot more type hints.
|
||||
This will work with `rust-analyzer 2021-03-15` shipped in nightly `1.52.0-nightly (107896c32 2021-03-15)` or later.
|
||||
|
||||
To have `rust-analyzer` also work in the `clippy_dev` and `lintcheck` crates, add the following configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"rust-analyzer.linkedProjects": [
|
||||
"./Cargo.toml",
|
||||
"clippy_dev/Cargo.toml",
|
||||
"lintcheck/Cargo.toml",
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
[ra_homepage]: https://rust-analyzer.github.io/
|
||||
[6869]: https://github.com/rust-lang/rust-clippy/pull/6869
|
||||
|
||||
## How Clippy works
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ We start by opening the test file created at `tests/ui/foo_functions.rs`.
|
|||
Update the file with some examples to get started:
|
||||
|
||||
```rust
|
||||
#![allow(unused)]
|
||||
#![warn(clippy::foo_functions)]
|
||||
|
||||
// Impl methods
|
||||
|
|
|
@ -123,7 +123,8 @@ There are three ways to do this, depending on if the target trait has a
|
|||
diagnostic item, lang item or neither.
|
||||
|
||||
```rust
|
||||
use clippy_utils::{implements_trait, is_trait_method, match_trait_method, paths};
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::is_trait_method;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
impl LateLintPass<'_> for MyStructLint {
|
||||
|
@ -143,13 +144,6 @@ impl LateLintPass<'_> for MyStructLint {
|
|||
.map_or(false, |id| implements_trait(cx, ty, id, &[])) {
|
||||
// `expr` implements `Drop` trait
|
||||
}
|
||||
|
||||
// 3. Using the type path with the expression
|
||||
// we use `match_trait_method` function from Clippy's utils
|
||||
// (This method should be avoided if possible)
|
||||
if match_trait_method(cx, expr, &paths::INTO) {
|
||||
// `expr` implements `Into` trait
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -233,8 +227,9 @@ functions to deal with macros:
|
|||
crates
|
||||
|
||||
```rust
|
||||
#[macro_use]
|
||||
extern crate a_crate_with_macros;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
|
||||
use a_crate_with_macros::foo;
|
||||
|
||||
// `foo` is defined in `a_crate_with_macros`
|
||||
foo!("bar");
|
||||
|
|
|
@ -188,6 +188,7 @@ pub(crate) fn get_stabilization_version() -> String {
|
|||
fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String {
|
||||
let mut contents = format!(
|
||||
indoc! {"
|
||||
#![allow(unused)]
|
||||
#![warn(clippy::{})]
|
||||
|
||||
fn main() {{
|
||||
|
|
|
@ -4,6 +4,7 @@ use clippy_utils::{meets_msrv, msrvs};
|
|||
use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::Span;
|
||||
|
@ -79,6 +80,7 @@ fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg
|
|||
(LitKind::Byte(b'a') | LitKind::Char('a'), LitKind::Byte(b'z') | LitKind::Char('z'))
|
||||
| (LitKind::Byte(b'A') | LitKind::Char('A'), LitKind::Byte(b'Z') | LitKind::Char('Z'))
|
||||
)
|
||||
&& !in_external_macro(cx.sess(), span)
|
||||
{
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
|
||||
use clippy_utils::path_res;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::{implements_trait, is_copy, is_type_diagnostic_item};
|
||||
use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item};
|
||||
use clippy_utils::usage::local_used_after_expr;
|
||||
use clippy_utils::{is_expr_final_block_expr, path_res};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
|
@ -58,6 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
|
|||
return;
|
||||
}
|
||||
}
|
||||
let semicolon = if is_expr_final_block_expr(cx.tcx, e) {";"} else {""};
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
match method_segment.ident.as_str() {
|
||||
"is_ok" if type_suitable_to_unwrap(cx, substs.type_at(1)) => {
|
||||
|
@ -68,8 +69,9 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
|
|||
"called `assert!` with `Result::is_ok`",
|
||||
"replace with",
|
||||
format!(
|
||||
"{}.unwrap()",
|
||||
snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
|
||||
"{}.unwrap(){}",
|
||||
snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0,
|
||||
semicolon
|
||||
),
|
||||
app,
|
||||
);
|
||||
|
@ -82,8 +84,9 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
|
|||
"called `assert!` with `Result::is_err`",
|
||||
"replace with",
|
||||
format!(
|
||||
"{}.unwrap_err()",
|
||||
snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0
|
||||
"{}.unwrap_err(){}",
|
||||
snippet_with_context(cx, recv.span, condition.span.ctxt(), "..", &mut app).0,
|
||||
semicolon
|
||||
),
|
||||
app,
|
||||
);
|
||||
|
@ -94,13 +97,6 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
|
|||
}
|
||||
}
|
||||
|
||||
/// This checks whether a given type is known to implement Debug.
|
||||
fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
cx.tcx
|
||||
.get_diagnostic_item(sym::Debug)
|
||||
.map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
|
||||
}
|
||||
|
||||
fn type_suitable_to_unwrap<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
has_debug_impl(cx, ty) && !ty.is_unit() && !ty.is_never()
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use rustc_ast::{ExprPrecedence, LitKind};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_hir::{Block, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
use clippy_utils::{diagnostics::span_lint_and_then, is_else_clause, source::snippet_block_with_applicability};
|
||||
use clippy_utils::{diagnostics::span_lint_and_then, is_else_clause, sugg::Sugg};
|
||||
use rustc_errors::Applicability;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
@ -55,27 +55,42 @@ fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx
|
|||
if let ExprKind::If(check, then, Some(else_)) = expr.kind
|
||||
&& let Some(then_lit) = int_literal(then)
|
||||
&& let Some(else_lit) = int_literal(else_)
|
||||
&& check_int_literal_equals_val(then_lit, 1)
|
||||
&& check_int_literal_equals_val(else_lit, 0)
|
||||
{
|
||||
let inverted = if
|
||||
check_int_literal_equals_val(then_lit, 1)
|
||||
&& check_int_literal_equals_val(else_lit, 0) {
|
||||
false
|
||||
} else if
|
||||
check_int_literal_equals_val(then_lit, 0)
|
||||
&& check_int_literal_equals_val(else_lit, 1) {
|
||||
true
|
||||
} else {
|
||||
// Expression isn't boolean, exit
|
||||
return;
|
||||
};
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let snippet = snippet_block_with_applicability(ctx, check.span, "..", None, &mut applicability);
|
||||
let snippet_with_braces = {
|
||||
let need_parens = should_have_parentheses(check);
|
||||
let (left_paren, right_paren) = if need_parens {("(", ")")} else {("", "")};
|
||||
format!("{left_paren}{snippet}{right_paren}")
|
||||
let snippet = {
|
||||
let mut sugg = Sugg::hir_with_applicability(ctx, check, "..", &mut applicability);
|
||||
if inverted {
|
||||
sugg = !sugg;
|
||||
}
|
||||
sugg
|
||||
};
|
||||
|
||||
let ty = ctx.typeck_results().expr_ty(then_lit); // then and else must be of same type
|
||||
|
||||
let suggestion = {
|
||||
let wrap_in_curly = is_else_clause(ctx.tcx, expr);
|
||||
let (left_curly, right_curly) = if wrap_in_curly {("{", "}")} else {("", "")};
|
||||
format!(
|
||||
"{left_curly}{ty}::from({snippet}){right_curly}"
|
||||
)
|
||||
let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into());
|
||||
if wrap_in_curly {
|
||||
s = s.blockify();
|
||||
}
|
||||
s
|
||||
}; // when used in else clause if statement should be wrapped in curly braces
|
||||
|
||||
let into_snippet = snippet.clone().maybe_par();
|
||||
let as_snippet = snippet.as_ty(ty);
|
||||
|
||||
span_lint_and_then(ctx,
|
||||
BOOL_TO_INT_WITH_IF,
|
||||
expr.span,
|
||||
|
@ -87,7 +102,7 @@ fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx
|
|||
suggestion,
|
||||
applicability,
|
||||
);
|
||||
diag.note(format!("`{snippet_with_braces} as {ty}` or `{snippet_with_braces}.into()` can also be valid options"));
|
||||
diag.note(format!("`{as_snippet}` or `{into_snippet}.into()` can also be valid options"));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@ -119,7 +134,3 @@ fn check_int_literal_equals_val<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>, expecte
|
|||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn should_have_parentheses<'tcx>(check: &'tcx rustc_hir::Expr<'tcx>) -> bool {
|
||||
check.precedence().order() < ExprPrecedence::Cast.order()
|
||||
}
|
||||
|
|
|
@ -237,7 +237,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
|
|||
}
|
||||
},
|
||||
&Term(n) => {
|
||||
let snip = snippet_opt(self.cx, self.terminals[n as usize].span)?;
|
||||
let snip = snippet_opt(self.cx, self.terminals[n as usize].span.source_callsite())?;
|
||||
self.output.push_str(&snip);
|
||||
},
|
||||
}
|
||||
|
|
|
@ -297,13 +297,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
|
|||
if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
|
||||
&& position.lint_explicit_deref() =>
|
||||
{
|
||||
let ty_changed_count = usize::from(!deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)));
|
||||
self.state = Some((
|
||||
State::DerefMethod {
|
||||
ty_changed_count: if deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)) {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
},
|
||||
ty_changed_count,
|
||||
is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
|
||||
target_mut,
|
||||
},
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::{is_default_equivalent, peel_blocks};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{
|
||||
def::{DefKind, Res},
|
||||
Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
|
||||
|
@ -100,15 +101,28 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
|
|||
ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if should_emit {
|
||||
let path_string = cx.tcx.def_path_str(adt_def.did());
|
||||
span_lint_and_help(
|
||||
let struct_span = cx.tcx.def_span(adt_def.did());
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
DERIVABLE_IMPLS,
|
||||
item.span,
|
||||
"this `impl` can be derived",
|
||||
None,
|
||||
&format!("try annotating `{}` with `#[derive(Default)]`", path_string),
|
||||
|diag| {
|
||||
diag.span_suggestion_hidden(
|
||||
item.span,
|
||||
"remove the manual implementation...",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
diag.span_suggestion(
|
||||
struct_span.shrink_to_lo(),
|
||||
"...and instead derive it",
|
||||
"#[derive(Default)]\n".to_string(),
|
||||
Applicability::MachineApplicable
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,12 +71,12 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
|
|||
let value = arg.param.value;
|
||||
if_chain! {
|
||||
if format_args.format_string.parts == [kw::Empty];
|
||||
if arg.format.is_default();
|
||||
if match cx.typeck_results().expr_ty(value).peel_refs().kind() {
|
||||
ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did()),
|
||||
ty::Str => true,
|
||||
_ => false,
|
||||
};
|
||||
if !arg.format.has_string_formatting();
|
||||
then {
|
||||
let is_new_string = match value.kind {
|
||||
ExprKind::Binary(..) => true,
|
||||
|
|
|
@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs {
|
|||
if let ExpnKind::Macro(_, name) = outermost_expn_data.kind;
|
||||
then {
|
||||
for arg in &format_args.args {
|
||||
if arg.format.has_string_formatting() {
|
||||
if !arg.format.is_default() {
|
||||
continue;
|
||||
}
|
||||
if is_aliased(&format_args, arg.param.value.hir_id) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::source::snippet;
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty::{self, ConstKind};
|
||||
|
@ -39,29 +38,28 @@ impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if_chain! {
|
||||
if let ExprKind::Repeat(_, _) = expr.kind;
|
||||
if let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind();
|
||||
if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind();
|
||||
if let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx);
|
||||
if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes());
|
||||
if self.maximum_allowed_size < element_count * element_size;
|
||||
then {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
LARGE_STACK_ARRAYS,
|
||||
expr.span,
|
||||
&format!(
|
||||
"allocating a local array larger than {} bytes",
|
||||
self.maximum_allowed_size
|
||||
),
|
||||
None,
|
||||
&format!(
|
||||
"consider allocating on the heap with `vec!{}.into_boxed_slice()`",
|
||||
snippet(cx, expr.span, "[...]")
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
if let ExprKind::Repeat(_, _) = expr.kind
|
||||
&& let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind()
|
||||
&& let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind()
|
||||
&& let Ok(element_count) = element_count.try_to_machine_usize(cx.tcx)
|
||||
&& let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
|
||||
&& !cx.tcx.hir().parent_iter(expr.hir_id)
|
||||
.any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. })))
|
||||
&& self.maximum_allowed_size < element_count * element_size {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
LARGE_STACK_ARRAYS,
|
||||
expr.span,
|
||||
&format!(
|
||||
"allocating a local array larger than {} bytes",
|
||||
self.maximum_allowed_size
|
||||
),
|
||||
None,
|
||||
&format!(
|
||||
"consider allocating on the heap with `vec!{}.into_boxed_slice()`",
|
||||
snippet(cx, expr.span, "[...]")
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,6 +171,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
|||
LintId::of(methods::ITERATOR_STEP_BY_ZERO),
|
||||
LintId::of(methods::ITER_CLONED_COLLECT),
|
||||
LintId::of(methods::ITER_COUNT),
|
||||
LintId::of(methods::ITER_KV_MAP),
|
||||
LintId::of(methods::ITER_NEXT_SLICE),
|
||||
LintId::of(methods::ITER_NTH),
|
||||
LintId::of(methods::ITER_NTH_ZERO),
|
||||
|
@ -351,7 +352,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
|||
LintId::of(useless_conversion::USELESS_CONVERSION),
|
||||
LintId::of(vec::USELESS_VEC),
|
||||
LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
|
||||
LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS),
|
||||
LintId::of(write::PRINTLN_EMPTY_STRING),
|
||||
LintId::of(write::PRINT_LITERAL),
|
||||
LintId::of(write::PRINT_WITH_NEWLINE),
|
||||
|
|
|
@ -40,6 +40,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
|
|||
LintId::of(methods::GET_LAST_WITH_LEN),
|
||||
LintId::of(methods::INSPECT_FOR_EACH),
|
||||
LintId::of(methods::ITER_COUNT),
|
||||
LintId::of(methods::ITER_KV_MAP),
|
||||
LintId::of(methods::MANUAL_FILTER_MAP),
|
||||
LintId::of(methods::MANUAL_FIND_MAP),
|
||||
LintId::of(methods::MANUAL_SPLIT_ONCE),
|
||||
|
|
|
@ -313,6 +313,7 @@ store.register_lints(&[
|
|||
methods::ITERATOR_STEP_BY_ZERO,
|
||||
methods::ITER_CLONED_COLLECT,
|
||||
methods::ITER_COUNT,
|
||||
methods::ITER_KV_MAP,
|
||||
methods::ITER_NEXT_SLICE,
|
||||
methods::ITER_NTH,
|
||||
methods::ITER_NTH_ZERO,
|
||||
|
@ -595,7 +596,6 @@ store.register_lints(&[
|
|||
vec_init_then_push::VEC_INIT_THEN_PUSH,
|
||||
wildcard_imports::ENUM_GLOB_USE,
|
||||
wildcard_imports::WILDCARD_IMPORTS,
|
||||
write::POSITIONAL_NAMED_FORMAT_PARAMETERS,
|
||||
write::PRINTLN_EMPTY_STRING,
|
||||
write::PRINT_LITERAL,
|
||||
write::PRINT_STDERR,
|
||||
|
|
|
@ -35,5 +35,4 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
|
|||
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
|
||||
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
|
||||
LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF),
|
||||
LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS),
|
||||
])
|
||||
|
|
|
@ -40,7 +40,6 @@ extern crate rustc_lint;
|
|||
extern crate rustc_middle;
|
||||
extern crate rustc_mir_dataflow;
|
||||
extern crate rustc_parse;
|
||||
extern crate rustc_parse_format;
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
extern crate rustc_target;
|
||||
|
@ -425,7 +424,6 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se
|
|||
})
|
||||
});
|
||||
|
||||
store.register_pre_expansion_pass(|| Box::new(write::Write::default()));
|
||||
store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv }));
|
||||
}
|
||||
|
||||
|
@ -524,7 +522,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
#[cfg(feature = "internal")]
|
||||
{
|
||||
if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
|
||||
store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
|
||||
store.register_late_pass(|_| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -879,6 +877,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
ignore_publish: cargo_ignore_publish,
|
||||
})
|
||||
});
|
||||
store.register_late_pass(|_| Box::new(write::Write::default()));
|
||||
store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
|
||||
store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets));
|
||||
store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::ERR_EXPECT;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::ty::has_debug_impl;
|
||||
use clippy_utils::{meets_msrv, msrvs, ty::is_type_diagnostic_item};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::LateContext;
|
||||
|
@ -28,7 +28,7 @@ pub(super) fn check(
|
|||
// Tests if the T type in a `Result<T, E>` is not None
|
||||
if let Some(data_type) = get_data_type(cx, result_type);
|
||||
// Tests if the T type in a `Result<T, E>` implements debug
|
||||
if has_debug_impl(data_type, cx);
|
||||
if has_debug_impl(cx, data_type);
|
||||
|
||||
then {
|
||||
span_lint_and_sugg(
|
||||
|
@ -51,10 +51,3 @@ fn get_data_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a type, very if the Debug trait has been impl'd
|
||||
fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
|
||||
cx.tcx
|
||||
.get_diagnostic_item(sym::Debug)
|
||||
.map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
|
||||
}
|
||||
|
|
87
clippy_lints/src/methods/iter_kv_map.rs
Normal file
87
clippy_lints/src/methods/iter_kv_map.rs
Normal file
|
@ -0,0 +1,87 @@
|
|||
#![allow(unused_imports)]
|
||||
|
||||
use super::ITER_KV_MAP;
|
||||
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||
use clippy_utils::sugg;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use rustc_hir::{BindingAnnotation, Body, BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::sym;
|
||||
use rustc_span::Span;
|
||||
|
||||
/// lint use of:
|
||||
/// - `hashmap.iter().map(|(_, v)| v)`
|
||||
/// - `hashmap.into_iter().map(|(_, v)| v)`
|
||||
/// on `HashMaps` and `BTreeMaps` in std
|
||||
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
map_type: &'tcx str, // iter / into_iter
|
||||
expr: &'tcx Expr<'tcx>, // .iter().map(|(_, v_| v))
|
||||
recv: &'tcx Expr<'tcx>, // hashmap
|
||||
m_arg: &'tcx Expr<'tcx>, // |(_, v)| v
|
||||
) {
|
||||
if_chain! {
|
||||
if !expr.span.from_expansion();
|
||||
if let ExprKind::Closure(c) = m_arg.kind;
|
||||
if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body);
|
||||
if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind;
|
||||
|
||||
let (replacement_kind, binded_ident) = match (&key_pat.kind, &val_pat.kind) {
|
||||
(key, PatKind::Binding(_, _, value, _)) if pat_is_wild(cx, key, m_arg) => ("value", value),
|
||||
(PatKind::Binding(_, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", key),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let ty = cx.typeck_results().expr_ty(recv);
|
||||
if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap);
|
||||
|
||||
then {
|
||||
let mut applicability = rustc_errors::Applicability::MachineApplicable;
|
||||
let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability);
|
||||
let into_prefix = if map_type == "into_iter" {"into_"} else {""};
|
||||
|
||||
if_chain! {
|
||||
if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind;
|
||||
if let [local_ident] = path.segments;
|
||||
if local_ident.ident.as_str() == binded_ident.as_str();
|
||||
|
||||
then {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
ITER_KV_MAP,
|
||||
expr.span,
|
||||
&format!("iterating on a map's {}s", replacement_kind),
|
||||
"try",
|
||||
format!("{}.{}{}s()", recv_snippet, into_prefix, replacement_kind),
|
||||
applicability,
|
||||
);
|
||||
} else {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
ITER_KV_MAP,
|
||||
expr.span,
|
||||
&format!("iterating on a map's {}s", replacement_kind),
|
||||
"try",
|
||||
format!("{}.{}{}s().map(|{}| {})", recv_snippet, into_prefix, replacement_kind, binded_ident,
|
||||
snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_`
|
||||
/// that is not locally used.
|
||||
fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool {
|
||||
match *pat {
|
||||
PatKind::Wild => true,
|
||||
PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id),
|
||||
_ => false,
|
||||
}
|
||||
}
|
|
@ -35,6 +35,7 @@ mod into_iter_on_ref;
|
|||
mod is_digit_ascii_radix;
|
||||
mod iter_cloned_collect;
|
||||
mod iter_count;
|
||||
mod iter_kv_map;
|
||||
mod iter_next_slice;
|
||||
mod iter_nth;
|
||||
mod iter_nth_zero;
|
||||
|
@ -3036,6 +3037,37 @@ declare_clippy_lint! {
|
|||
"use of `File::read_to_end` or `File::read_to_string`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
///
|
||||
/// Checks for iterating a map (`HashMap` or `BTreeMap`) and
|
||||
/// ignoring either the keys or values.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// Readability. There are `keys` and `values` methods that
|
||||
/// can be used to express that we only need the keys or the values.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```
|
||||
/// # use std::collections::HashMap;
|
||||
/// let map: HashMap<u32, u32> = HashMap::new();
|
||||
/// let values = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```
|
||||
/// # use std::collections::HashMap;
|
||||
/// let map: HashMap<u32, u32> = HashMap::new();
|
||||
/// let values = map.values().collect::<Vec<_>>();
|
||||
/// ```
|
||||
#[clippy::version = "1.65.0"]
|
||||
pub ITER_KV_MAP,
|
||||
complexity,
|
||||
"iterating on map using `iter` when `keys` or `values` would do"
|
||||
}
|
||||
|
||||
pub struct Methods {
|
||||
avoid_breaking_exported_api: bool,
|
||||
msrv: Option<RustcVersion>,
|
||||
|
@ -3159,6 +3191,7 @@ impl_lint_pass!(Methods => [
|
|||
UNNECESSARY_SORT_BY,
|
||||
VEC_RESIZE_TO_ZERO,
|
||||
VERBOSE_FILE_READS,
|
||||
ITER_KV_MAP,
|
||||
]);
|
||||
|
||||
/// Extracts a method call name, args, and `Span` of the method name.
|
||||
|
@ -3498,6 +3531,9 @@ impl Methods {
|
|||
(name @ ("map" | "map_err"), [m_arg]) => {
|
||||
if name == "map" {
|
||||
map_clone::check(cx, expr, recv, m_arg, self.msrv);
|
||||
if let Some((map_name @ ("iter" | "into_iter"), recv2, _, _)) = method_call(recv) {
|
||||
iter_kv_map::check(cx, map_name, expr, recv2, m_arg);
|
||||
}
|
||||
} else {
|
||||
map_err_ignore::check(cx, expr, m_arg);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
|
@ -15,7 +15,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
|
|||
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
|
||||
let result_type = cx.typeck_results().expr_ty(recv);
|
||||
if let Some(error_type) = get_error_type(cx, result_type);
|
||||
if has_debug_impl(error_type, cx);
|
||||
if has_debug_impl(cx, error_type);
|
||||
|
||||
then {
|
||||
span_lint_and_help(
|
||||
|
@ -37,10 +37,3 @@ fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// This checks whether a given type is known to implement Debug.
|
||||
fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
|
||||
cx.tcx
|
||||
.get_diagnostic_item(sym::Debug)
|
||||
.map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use clippy_utils::visitors::find_all_ret_expressions;
|
|||
use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
|
||||
use clippy_utils::{meets_msrv, msrvs};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node};
|
||||
use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::mir::Mutability;
|
||||
|
@ -268,7 +268,7 @@ fn check_other_call_arg<'tcx>(
|
|||
// We can't add an `&` when the trait is `Deref` because `Target = &T` won't match
|
||||
// `Target = T`.
|
||||
if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id;
|
||||
let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 });
|
||||
let n_refs = max(n_refs, usize::from(!is_copy(cx, receiver_ty)));
|
||||
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
|
||||
then {
|
||||
span_lint_and_sugg(
|
||||
|
@ -379,6 +379,10 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
|
|||
Node::Expr(parent_expr) => {
|
||||
if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr)
|
||||
{
|
||||
if cx.tcx.lang_items().require(LangItem::IntoFutureIntoFuture) == Ok(callee_def_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
|
||||
if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
|
||||
&& let Some(param_ty) = fn_sig.inputs().get(arg_index)
|
||||
|
|
|
@ -2,7 +2,7 @@ use rustc_ast::ast;
|
|||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{FileName, RealFileName, SourceFile, Span, SyntaxContext};
|
||||
use rustc_span::{FileName, SourceFile, Span, SyntaxContext};
|
||||
use std::ffi::OsStr;
|
||||
use std::path::{Component, Path};
|
||||
|
||||
|
@ -79,7 +79,7 @@ impl EarlyLintPass for ModStyle {
|
|||
|
||||
let files = cx.sess().source_map().files();
|
||||
|
||||
let RealFileName::LocalPath(trim_to_src) = &cx.sess().opts.working_dir else { return };
|
||||
let Some(trim_to_src) = cx.sess().opts.working_dir.local_path() else { return };
|
||||
|
||||
// `folder_segments` is all unique folder path segments `path/to/foo.rs` gives
|
||||
// `[path, to]` but not foo
|
||||
|
@ -90,7 +90,7 @@ impl EarlyLintPass for ModStyle {
|
|||
// `{ foo => path/to/foo.rs, .. }
|
||||
let mut file_map = FxHashMap::default();
|
||||
for file in files.iter() {
|
||||
if let FileName::Real(RealFileName::LocalPath(lp)) = &file.name {
|
||||
if let FileName::Real(name) = &file.name && let Some(lp) = name.local_path() {
|
||||
let path = if lp.is_relative() {
|
||||
lp
|
||||
} else if let Ok(relative) = lp.strip_prefix(trim_to_src) {
|
||||
|
|
|
@ -184,6 +184,10 @@ fn macro_braces(conf: FxHashSet<MacroMatcher>) -> FxHashMap<String, (String, Str
|
|||
name: "vec",
|
||||
braces: ("[", "]"),
|
||||
),
|
||||
macro_matcher!(
|
||||
name: "matches",
|
||||
braces: ("(", ")"),
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.collect::<FxHashMap<_, _>>();
|
||||
|
|
|
@ -42,27 +42,30 @@ impl ArithmeticSideEffects {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks assign operators (+=, -=, *=, /=) of integers in a non-constant environment that
|
||||
/// won't overflow.
|
||||
fn has_valid_assign_op(op: &Spanned<hir::BinOpKind>, rhs: &hir::Expr<'_>, rhs_refs: Ty<'_>) -> bool {
|
||||
if !Self::is_literal_integer(rhs, rhs_refs) {
|
||||
return false;
|
||||
/// Assuming that `expr` is a literal integer, checks operators (+=, -=, *, /) in a
|
||||
/// non-constant environment that won't overflow.
|
||||
fn has_valid_op(op: &Spanned<hir::BinOpKind>, expr: &hir::Expr<'_>) -> bool {
|
||||
if let hir::BinOpKind::Add | hir::BinOpKind::Sub = op.node
|
||||
&& let hir::ExprKind::Lit(ref lit) = expr.kind
|
||||
&& let ast::LitKind::Int(0, _) = lit.node
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if let hir::BinOpKind::Div | hir::BinOpKind::Mul = op.node
|
||||
&& let hir::ExprKind::Lit(ref lit) = rhs.kind
|
||||
&& let ast::LitKind::Int(1, _) = lit.node
|
||||
if let hir::BinOpKind::Div | hir::BinOpKind::Rem = op.node
|
||||
&& let hir::ExprKind::Lit(ref lit) = expr.kind
|
||||
&& !matches!(lit.node, ast::LitKind::Int(0, _))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if let hir::BinOpKind::Mul = op.node
|
||||
&& let hir::ExprKind::Lit(ref lit) = expr.kind
|
||||
&& let ast::LitKind::Int(0 | 1, _) = lit.node
|
||||
{
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Checks "raw" binary operators (+, -, *, /) of integers in a non-constant environment
|
||||
/// already handled by the CTFE.
|
||||
fn has_valid_bin_op(lhs: &hir::Expr<'_>, lhs_refs: Ty<'_>, rhs: &hir::Expr<'_>, rhs_refs: Ty<'_>) -> bool {
|
||||
Self::is_literal_integer(lhs, lhs_refs) && Self::is_literal_integer(rhs, rhs_refs)
|
||||
}
|
||||
|
||||
/// Checks if the given `expr` has any of the inner `allowed` elements.
|
||||
fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
|
||||
self.allowed.contains(
|
||||
|
@ -83,7 +86,8 @@ impl ArithmeticSideEffects {
|
|||
}
|
||||
|
||||
fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
|
||||
span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, "arithmetic detected");
|
||||
let msg = "arithmetic operation that can potentially result in unexpected side-effects";
|
||||
span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, msg);
|
||||
self.expr_span = Some(expr.span);
|
||||
}
|
||||
|
||||
|
@ -115,13 +119,18 @@ impl ArithmeticSideEffects {
|
|||
if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) {
|
||||
return;
|
||||
}
|
||||
let lhs_refs = cx.typeck_results().expr_ty(lhs).peel_refs();
|
||||
let rhs_refs = cx.typeck_results().expr_ty(rhs).peel_refs();
|
||||
let has_valid_assign_op = Self::has_valid_assign_op(op, rhs, rhs_refs);
|
||||
if has_valid_assign_op || Self::has_valid_bin_op(lhs, lhs_refs, rhs, rhs_refs) {
|
||||
return;
|
||||
let has_valid_op = match (
|
||||
Self::is_literal_integer(lhs, cx.typeck_results().expr_ty(lhs).peel_refs()),
|
||||
Self::is_literal_integer(rhs, cx.typeck_results().expr_ty(rhs).peel_refs()),
|
||||
) {
|
||||
(true, true) => true,
|
||||
(true, false) => Self::has_valid_op(op, lhs),
|
||||
(false, true) => Self::has_valid_op(op, rhs),
|
||||
(false, false) => false,
|
||||
};
|
||||
if !has_valid_op {
|
||||
self.issue_lint(cx, expr);
|
||||
}
|
||||
self.issue_lint(cx, expr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
|
|||
("clippy::invalid_ref", "invalid_value"),
|
||||
("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
|
||||
("clippy::panic_params", "non_fmt_panics"),
|
||||
("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
|
||||
("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
|
||||
("clippy::unknown_clippy_lints", "unknown_lints"),
|
||||
("clippy::unused_label", "unused_labels"),
|
||||
|
|
|
@ -6,6 +6,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor};
|
|||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
||||
|
@ -109,8 +110,14 @@ impl<'a, 'tcx> PeekableVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'_ Expr<'_>) {
|
||||
impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
|
||||
type NestedFilter = OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
|
||||
if self.found_peek_call {
|
||||
return;
|
||||
}
|
||||
|
@ -136,12 +143,11 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
if args.iter().any(|arg| {
|
||||
matches!(arg.kind, ExprKind::Path(_)) && arg_is_mut_peekable(self.cx, arg)
|
||||
}) {
|
||||
if args.iter().any(|arg| arg_is_mut_peekable(self.cx, arg)) {
|
||||
self.found_peek_call = true;
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
},
|
||||
// Catch anything taking a Peekable mutably
|
||||
ExprKind::MethodCall(
|
||||
|
@ -190,21 +196,21 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> {
|
|||
Node::Local(Local { init: Some(init), .. }) => {
|
||||
if arg_is_mut_peekable(self.cx, init) {
|
||||
self.found_peek_call = true;
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
return;
|
||||
},
|
||||
Node::Stmt(stmt) => match stmt.kind {
|
||||
StmtKind::Expr(_) | StmtKind::Semi(_) => {},
|
||||
_ => {
|
||||
self.found_peek_call = true;
|
||||
return;
|
||||
},
|
||||
Node::Stmt(stmt) => {
|
||||
match stmt.kind {
|
||||
StmtKind::Local(_) | StmtKind::Item(_) => self.found_peek_call = true,
|
||||
StmtKind::Expr(_) | StmtKind::Semi(_) => {},
|
||||
}
|
||||
|
||||
return;
|
||||
},
|
||||
Node::Block(_) | Node::ExprField(_) => {},
|
||||
_ => {
|
||||
break;
|
||||
return;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::ty::same_type_and_consts;
|
||||
use clippy_utils::{meets_msrv, msrvs};
|
||||
use clippy_utils::{is_from_proc_macro, meets_msrv, msrvs};
|
||||
use if_chain::if_chain;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
|
@ -87,7 +87,7 @@ impl_lint_pass!(UseSelf => [USE_SELF]);
|
|||
const SEGMENTS_MSG: &str = "segments should be composed of at least 1 element";
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for UseSelf {
|
||||
fn check_item(&mut self, _cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
|
||||
if matches!(item.kind, ItemKind::OpaqueTy(_)) {
|
||||
// skip over `ItemKind::OpaqueTy` in order to lint `foo() -> impl <..>`
|
||||
return;
|
||||
|
@ -103,6 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
|
|||
if parameters.as_ref().map_or(true, |params| {
|
||||
!params.parenthesized && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
|
||||
});
|
||||
if !is_from_proc_macro(cx, item); // expensive, should be last check
|
||||
then {
|
||||
StackItem::Check {
|
||||
impl_id: item.def_id,
|
||||
|
@ -213,9 +214,6 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
|
|||
hir_ty_to_ty(cx.tcx, hir_ty)
|
||||
};
|
||||
if same_type_and_consts(ty, cx.tcx.type_of(impl_id));
|
||||
let hir = cx.tcx.hir();
|
||||
// prevents false positive on `#[derive(serde::Deserialize)]`
|
||||
if !hir.span(hir.get_parent_node(hir_ty.hir_id)).in_derive_expansion();
|
||||
then {
|
||||
span_lint(cx, hir_ty.span);
|
||||
}
|
||||
|
|
|
@ -476,7 +476,7 @@ pub fn format_error(error: Box<dyn Error>) -> String {
|
|||
|
||||
let mut msg = String::from(prefix);
|
||||
for row in 0..rows {
|
||||
write!(msg, "\n").unwrap();
|
||||
writeln!(msg).unwrap();
|
||||
for (column, column_width) in column_widths.iter().copied().enumerate() {
|
||||
let index = column * rows + row;
|
||||
let field = fields.get(index).copied().unwrap_or_default();
|
||||
|
|
|
@ -1,20 +1,12 @@
|
|||
use std::borrow::Cow;
|
||||
use std::iter;
|
||||
use std::ops::{Deref, Range};
|
||||
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
|
||||
use rustc_ast::ast::{Expr, ExprKind, Impl, Item, ItemKind, MacCall, Path, StrLit, StrStyle};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, LitKind};
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_lexer::unescape::{self, EscapeError};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_parse::parser;
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
||||
use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn, MacroCall};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, HirIdMap, Impl, Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::{sym, BytePos, InnerSpan, Span, DUMMY_SP};
|
||||
use rustc_span::{sym, BytePos, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -74,13 +66,7 @@ declare_clippy_lint! {
|
|||
/// application and might forget to remove those prints afterward.
|
||||
///
|
||||
/// ### Known problems
|
||||
/// * Only catches `print!` and `println!` calls.
|
||||
/// * The lint level is unaffected by crate attributes. The level can still
|
||||
/// be set for functions, modules and other items. To change the level for
|
||||
/// the entire crate, please use command line flags. More information and a
|
||||
/// configuration example can be found in [clippy#6610].
|
||||
///
|
||||
/// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
|
||||
/// Only catches `print!` and `println!` calls.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
|
@ -102,13 +88,7 @@ declare_clippy_lint! {
|
|||
/// application and might forget to remove those prints afterward.
|
||||
///
|
||||
/// ### Known problems
|
||||
/// * Only catches `eprint!` and `eprintln!` calls.
|
||||
/// * The lint level is unaffected by crate attributes. The level can still
|
||||
/// be set for functions, modules and other items. To change the level for
|
||||
/// the entire crate, please use command line flags. More information and a
|
||||
/// configuration example can be found in [clippy#6610].
|
||||
///
|
||||
/// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
|
||||
/// Only catches `eprint!` and `eprintln!` calls.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
|
@ -149,10 +129,6 @@ declare_clippy_lint! {
|
|||
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
|
||||
/// (i.e., just put the literal in the format string)
|
||||
///
|
||||
/// ### Known problems
|
||||
/// Will also warn with macro calls as arguments that expand to literals
|
||||
/// -- e.g., `println!("{}", env!("FOO"))`.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// println!("{}", "foo");
|
||||
|
@ -234,10 +210,6 @@ declare_clippy_lint! {
|
|||
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
|
||||
/// (i.e., just put the literal in the format string)
|
||||
///
|
||||
/// ### Known problems
|
||||
/// Will also warn with macro calls as arguments that expand to literals
|
||||
/// -- e.g., `writeln!(buf, "{}", env!("FOO"))`.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # use std::fmt::Write;
|
||||
|
@ -257,28 +229,6 @@ declare_clippy_lint! {
|
|||
"writing a literal with a format string"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// This lint warns when a named parameter in a format string is used as a positional one.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// It may be confused for an assignment and obfuscates which parameter is being used.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// println!("{}", x = 10);
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// println!("{x}", x = 10);
|
||||
/// ```
|
||||
#[clippy::version = "1.63.0"]
|
||||
pub POSITIONAL_NAMED_FORMAT_PARAMETERS,
|
||||
suspicious,
|
||||
"named parameter in a format string is used positionally"
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Write {
|
||||
in_debug_impl: bool,
|
||||
|
@ -294,537 +244,308 @@ impl_lint_pass!(Write => [
|
|||
WRITE_WITH_NEWLINE,
|
||||
WRITELN_EMPTY_STRING,
|
||||
WRITE_LITERAL,
|
||||
POSITIONAL_NAMED_FORMAT_PARAMETERS,
|
||||
]);
|
||||
|
||||
impl EarlyLintPass for Write {
|
||||
fn check_item(&mut self, _: &EarlyContext<'_>, item: &Item) {
|
||||
if let ItemKind::Impl(box Impl {
|
||||
of_trait: Some(trait_ref),
|
||||
..
|
||||
}) = &item.kind
|
||||
{
|
||||
let trait_name = trait_ref
|
||||
.path
|
||||
.segments
|
||||
.iter()
|
||||
.last()
|
||||
.expect("path has at least one segment")
|
||||
.ident
|
||||
.name;
|
||||
if trait_name == sym::Debug {
|
||||
self.in_debug_impl = true;
|
||||
}
|
||||
impl<'tcx> LateLintPass<'tcx> for Write {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
if is_debug_impl(cx, item) {
|
||||
self.in_debug_impl = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &Item) {
|
||||
self.in_debug_impl = false;
|
||||
fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
if is_debug_impl(cx, item) {
|
||||
self.in_debug_impl = false;
|
||||
}
|
||||
}
|
||||
|
||||
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) {
|
||||
fn is_build_script(cx: &EarlyContext<'_>) -> bool {
|
||||
// Cargo sets the crate name for build scripts to `build_script_build`
|
||||
cx.sess()
|
||||
.opts
|
||||
.crate_name
|
||||
.as_ref()
|
||||
.map_or(false, |crate_name| crate_name == "build_script_build")
|
||||
}
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
|
||||
let Some(diag_name) = cx.tcx.get_diagnostic_name(macro_call.def_id) else { return };
|
||||
let Some(name) = diag_name.as_str().strip_suffix("_macro") else { return };
|
||||
|
||||
if mac.path == sym!(print) {
|
||||
if !is_build_script(cx) {
|
||||
span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`");
|
||||
}
|
||||
self.lint_print_with_newline(cx, mac);
|
||||
} else if mac.path == sym!(println) {
|
||||
if !is_build_script(cx) {
|
||||
span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
|
||||
}
|
||||
self.lint_println_empty_string(cx, mac);
|
||||
} else if mac.path == sym!(eprint) {
|
||||
span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprint!`");
|
||||
self.lint_print_with_newline(cx, mac);
|
||||
} else if mac.path == sym!(eprintln) {
|
||||
span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`");
|
||||
self.lint_println_empty_string(cx, mac);
|
||||
} else if mac.path == sym!(write) {
|
||||
if let (Some(fmt_str), dest) = self.check_tts(cx, mac.args.inner_tokens(), true) {
|
||||
if check_newlines(&fmt_str) {
|
||||
let (nl_span, only_nl) = newline_span(&fmt_str);
|
||||
let nl_span = match (dest, only_nl) {
|
||||
// Special case of `write!(buf, "\n")`: Mark everything from the end of
|
||||
// `buf` for removal so no trailing comma [`writeln!(buf, )`] remains.
|
||||
(Some(dest_expr), true) => nl_span.with_lo(dest_expr.span.hi()),
|
||||
_ => nl_span,
|
||||
};
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
WRITE_WITH_NEWLINE,
|
||||
mac.span(),
|
||||
"using `write!()` with a format string that ends in a single newline",
|
||||
|err| {
|
||||
err.multipart_suggestion(
|
||||
"use `writeln!()` instead",
|
||||
vec![(mac.path.span, String::from("writeln")), (nl_span, String::new())],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
},
|
||||
);
|
||||
let is_build_script = cx
|
||||
.sess()
|
||||
.opts
|
||||
.crate_name
|
||||
.as_ref()
|
||||
.map_or(false, |crate_name| crate_name == "build_script_build");
|
||||
|
||||
match diag_name {
|
||||
sym::print_macro | sym::println_macro => {
|
||||
if !is_build_script {
|
||||
span_lint(cx, PRINT_STDOUT, macro_call.span, &format!("use of `{name}!`"));
|
||||
}
|
||||
}
|
||||
} else if mac.path == sym!(writeln) {
|
||||
if let (Some(fmt_str), expr) = self.check_tts(cx, mac.args.inner_tokens(), true) {
|
||||
if fmt_str.symbol == kw::Empty {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let suggestion = if let Some(e) = expr {
|
||||
snippet_with_applicability(cx, e.span, "v", &mut applicability)
|
||||
} else {
|
||||
applicability = Applicability::HasPlaceholders;
|
||||
Cow::Borrowed("v")
|
||||
};
|
||||
},
|
||||
sym::eprint_macro | sym::eprintln_macro => {
|
||||
span_lint(cx, PRINT_STDERR, macro_call.span, &format!("use of `{name}!`"));
|
||||
},
|
||||
sym::write_macro | sym::writeln_macro => {},
|
||||
_ => return,
|
||||
}
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
WRITELN_EMPTY_STRING,
|
||||
mac.span(),
|
||||
format!("using `writeln!({}, \"\")`", suggestion).as_str(),
|
||||
"replace it with",
|
||||
format!("writeln!({})", suggestion),
|
||||
applicability,
|
||||
);
|
||||
let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn) else { return };
|
||||
|
||||
// ignore `writeln!(w)` and `write!(v, some_macro!())`
|
||||
if format_args.format_string.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
|
||||
match diag_name {
|
||||
sym::print_macro | sym::eprint_macro | sym::write_macro => {
|
||||
check_newline(cx, &format_args, ¯o_call, name);
|
||||
},
|
||||
sym::println_macro | sym::eprintln_macro | sym::writeln_macro => {
|
||||
check_empty_string(cx, &format_args, ¯o_call, name);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
check_literal(cx, &format_args, name);
|
||||
|
||||
if !self.in_debug_impl {
|
||||
for arg in &format_args.args {
|
||||
if arg.format.r#trait == sym::Debug {
|
||||
span_lint(cx, USE_DEBUG, arg.span, "use of `Debug`-based formatting");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a format string that ends in a newline and its span, calculates the span of the
|
||||
/// newline, or the format string itself if the format string consists solely of a newline.
|
||||
/// Return this and a boolean indicating whether it only consisted of a newline.
|
||||
fn newline_span(fmtstr: &StrLit) -> (Span, bool) {
|
||||
let sp = fmtstr.span;
|
||||
let contents = fmtstr.symbol.as_str();
|
||||
|
||||
if contents == r"\n" {
|
||||
return (sp, true);
|
||||
}
|
||||
|
||||
let newline_sp_hi = sp.hi()
|
||||
- match fmtstr.style {
|
||||
StrStyle::Cooked => BytePos(1),
|
||||
StrStyle::Raw(hashes) => BytePos((1 + hashes).into()),
|
||||
};
|
||||
|
||||
let newline_sp_len = if contents.ends_with('\n') {
|
||||
BytePos(1)
|
||||
} else if contents.ends_with(r"\n") {
|
||||
BytePos(2)
|
||||
fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
|
||||
if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), .. }) = &item.kind
|
||||
&& let Some(trait_id) = trait_ref.trait_def_id()
|
||||
{
|
||||
cx.tcx.is_diagnostic_item(sym::Debug, trait_id)
|
||||
} else {
|
||||
panic!("expected format string to contain a newline");
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_call: &MacroCall, name: &str) {
|
||||
let format_string_parts = &format_args.format_string.parts;
|
||||
let mut format_string_span = format_args.format_string.span;
|
||||
|
||||
let Some(last) = format_string_parts.last() else { return };
|
||||
|
||||
let count_vertical_whitespace = || {
|
||||
format_string_parts
|
||||
.iter()
|
||||
.flat_map(|part| part.as_str().chars())
|
||||
.filter(|ch| matches!(ch, '\r' | '\n'))
|
||||
.count()
|
||||
};
|
||||
|
||||
(sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi), false)
|
||||
}
|
||||
if last.as_str().ends_with('\n')
|
||||
// ignore format strings with other internal vertical whitespace
|
||||
&& count_vertical_whitespace() == 1
|
||||
|
||||
/// Stores a list of replacement spans for each argument, but only if all the replacements used an
|
||||
/// empty format string.
|
||||
#[derive(Default)]
|
||||
struct SimpleFormatArgs {
|
||||
unnamed: Vec<Vec<Span>>,
|
||||
complex_unnamed: Vec<Vec<Span>>,
|
||||
named: Vec<(Symbol, Vec<Span>)>,
|
||||
}
|
||||
impl SimpleFormatArgs {
|
||||
fn get_unnamed(&self) -> impl Iterator<Item = &[Span]> {
|
||||
self.unnamed.iter().map(|x| match x.as_slice() {
|
||||
// Ignore the dummy span added from out of order format arguments.
|
||||
[DUMMY_SP] => &[],
|
||||
x => x,
|
||||
})
|
||||
}
|
||||
// ignore trailing arguments: `print!("Issue\n{}", 1265);`
|
||||
&& format_string_parts.len() > format_args.args.len()
|
||||
{
|
||||
let lint = if name == "write" {
|
||||
format_string_span = expand_past_previous_comma(cx, format_string_span);
|
||||
|
||||
fn get_complex_unnamed(&self) -> impl Iterator<Item = &[Span]> {
|
||||
self.complex_unnamed.iter().map(Vec::as_slice)
|
||||
}
|
||||
|
||||
fn get_named(&self, n: &Path) -> &[Span] {
|
||||
self.named.iter().find(|x| *n == x.0).map_or(&[], |x| x.1.as_slice())
|
||||
}
|
||||
|
||||
fn push(&mut self, arg: rustc_parse_format::Argument<'_>, span: Span) {
|
||||
use rustc_parse_format::{
|
||||
AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec,
|
||||
WRITE_WITH_NEWLINE
|
||||
} else {
|
||||
PRINT_WITH_NEWLINE
|
||||
};
|
||||
|
||||
const SIMPLE: FormatSpec<'_> = FormatSpec {
|
||||
fill: None,
|
||||
align: AlignUnknown,
|
||||
flags: 0,
|
||||
precision: CountImplied,
|
||||
precision_span: None,
|
||||
width: CountImplied,
|
||||
width_span: None,
|
||||
ty: "",
|
||||
ty_span: None,
|
||||
};
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
lint,
|
||||
macro_call.span,
|
||||
&format!("using `{name}!()` with a format string that ends in a single newline"),
|
||||
|diag| {
|
||||
let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!');
|
||||
let Some(format_snippet) = snippet_opt(cx, format_string_span) else { return };
|
||||
|
||||
match arg.position {
|
||||
ArgumentIs(n) | ArgumentImplicitlyIs(n) => {
|
||||
if self.unnamed.len() <= n {
|
||||
// Use a dummy span to mark all unseen arguments.
|
||||
self.unnamed.resize_with(n, || vec![DUMMY_SP]);
|
||||
if arg.format == SIMPLE {
|
||||
self.unnamed.push(vec![span]);
|
||||
} else {
|
||||
self.unnamed.push(Vec::new());
|
||||
}
|
||||
} else {
|
||||
let args = &mut self.unnamed[n];
|
||||
match (args.as_mut_slice(), arg.format == SIMPLE) {
|
||||
// A non-empty format string has been seen already.
|
||||
([], _) => (),
|
||||
// Replace the dummy span, if it exists.
|
||||
([dummy @ DUMMY_SP], true) => *dummy = span,
|
||||
([_, ..], true) => args.push(span),
|
||||
([_, ..], false) => *args = Vec::new(),
|
||||
}
|
||||
if format_string_parts.len() == 1 && last.as_str() == "\n" {
|
||||
// print!("\n"), write!(f, "\n")
|
||||
|
||||
diag.multipart_suggestion(
|
||||
&format!("use `{name}ln!` instead"),
|
||||
vec![(name_span, format!("{name}ln")), (format_string_span, String::new())],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if format_snippet.ends_with("\\n\"") {
|
||||
// print!("...\n"), write!(f, "...\n")
|
||||
|
||||
let hi = format_string_span.hi();
|
||||
let newline_span = format_string_span.with_lo(hi - BytePos(3)).with_hi(hi - BytePos(1));
|
||||
|
||||
diag.multipart_suggestion(
|
||||
&format!("use `{name}ln!` instead"),
|
||||
vec![(name_span, format!("{name}ln")), (newline_span, String::new())],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
},
|
||||
ArgumentNamed(n) => {
|
||||
let n = Symbol::intern(n);
|
||||
if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) {
|
||||
match x.1.as_slice() {
|
||||
// A non-empty format string has been seen already.
|
||||
[] => (),
|
||||
[_, ..] if arg.format == SIMPLE => x.1.push(span),
|
||||
[_, ..] => x.1 = Vec::new(),
|
||||
}
|
||||
} else if arg.format == SIMPLE {
|
||||
self.named.push((n, vec![span]));
|
||||
} else {
|
||||
self.named.push((n, Vec::new()));
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn push_to_complex(&mut self, span: Span, position: usize) {
|
||||
if self.complex_unnamed.len() <= position {
|
||||
self.complex_unnamed.resize_with(position, Vec::new);
|
||||
self.complex_unnamed.push(vec![span]);
|
||||
} else {
|
||||
let args: &mut Vec<Span> = &mut self.complex_unnamed[position];
|
||||
args.push(span);
|
||||
}
|
||||
}
|
||||
|
||||
fn push_complex(
|
||||
&mut self,
|
||||
cx: &EarlyContext<'_>,
|
||||
arg: rustc_parse_format::Argument<'_>,
|
||||
str_lit_span: Span,
|
||||
fmt_span: Span,
|
||||
) {
|
||||
use rustc_parse_format::{ArgumentImplicitlyIs, ArgumentIs, CountIsParam, CountIsStar};
|
||||
|
||||
let snippet = snippet_opt(cx, fmt_span);
|
||||
|
||||
let end = snippet
|
||||
.as_ref()
|
||||
.and_then(|s| s.find(':'))
|
||||
.or_else(|| fmt_span.hi().0.checked_sub(fmt_span.lo().0 + 1).map(|u| u as usize));
|
||||
|
||||
if let (ArgumentIs(n) | ArgumentImplicitlyIs(n), Some(end)) = (arg.position, end) {
|
||||
let span = fmt_span.from_inner(InnerSpan::new(1, end));
|
||||
self.push_to_complex(span, n);
|
||||
};
|
||||
|
||||
if let (CountIsParam(n) | CountIsStar(n), Some(span)) = (arg.format.precision, arg.format.precision_span) {
|
||||
// We need to do this hack as precision spans should be converted from .* to .foo$
|
||||
let hack = if snippet.as_ref().and_then(|s| s.find('*')).is_some() {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
let span = str_lit_span.from_inner(InnerSpan {
|
||||
start: span.start + 1,
|
||||
end: span.end - hack,
|
||||
});
|
||||
self.push_to_complex(span, n);
|
||||
};
|
||||
|
||||
if let (CountIsParam(n), Some(span)) = (arg.format.width, arg.format.width_span) {
|
||||
let span = str_lit_span.from_inner(InnerSpan {
|
||||
start: span.start,
|
||||
end: span.end - 1,
|
||||
});
|
||||
self.push_to_complex(span, n);
|
||||
};
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl Write {
|
||||
/// Parses a format string into a collection of spans for each argument. This only keeps track
|
||||
/// of empty format arguments. Will also lint usages of debug format strings outside of debug
|
||||
/// impls.
|
||||
fn parse_fmt_string(&self, cx: &EarlyContext<'_>, str_lit: &StrLit) -> Option<SimpleFormatArgs> {
|
||||
use rustc_parse_format::{ParseMode, Parser, Piece};
|
||||
fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_call: &MacroCall, name: &str) {
|
||||
if let [part] = &format_args.format_string.parts[..]
|
||||
&& let mut span = format_args.format_string.span
|
||||
&& part.as_str() == "\n"
|
||||
{
|
||||
let lint = if name == "writeln" {
|
||||
span = expand_past_previous_comma(cx, span);
|
||||
|
||||
let str_sym = str_lit.symbol_unescaped.as_str();
|
||||
let style = match str_lit.style {
|
||||
StrStyle::Cooked => None,
|
||||
StrStyle::Raw(n) => Some(n as usize),
|
||||
};
|
||||
|
||||
let mut parser = Parser::new(str_sym, style, snippet_opt(cx, str_lit.span), false, ParseMode::Format);
|
||||
let mut args = SimpleFormatArgs::default();
|
||||
|
||||
while let Some(arg) = parser.next() {
|
||||
let arg = match arg {
|
||||
Piece::String(_) => continue,
|
||||
Piece::NextArgument(arg) => arg,
|
||||
};
|
||||
let span = parser
|
||||
.arg_places
|
||||
.last()
|
||||
.map_or(DUMMY_SP, |&x| str_lit.span.from_inner(InnerSpan::new(x.start, x.end)));
|
||||
|
||||
if !self.in_debug_impl && arg.format.ty == "?" {
|
||||
// FIXME: modify rustc's fmt string parser to give us the current span
|
||||
span_lint(cx, USE_DEBUG, span, "use of `Debug`-based formatting");
|
||||
}
|
||||
args.push(arg, span);
|
||||
args.push_complex(cx, arg, str_lit.span, span);
|
||||
}
|
||||
|
||||
parser.errors.is_empty().then_some(args)
|
||||
}
|
||||
|
||||
/// Checks the arguments of `print[ln]!` and `write[ln]!` calls. It will return a tuple of two
|
||||
/// `Option`s. The first `Option` of the tuple is the macro's format string. It includes
|
||||
/// the contents of the string, whether it's a raw string, and the span of the literal in the
|
||||
/// source. The second `Option` in the tuple is, in the `write[ln]!` case, the expression the
|
||||
/// `format_str` should be written to.
|
||||
///
|
||||
/// Example:
|
||||
///
|
||||
/// Calling this function on
|
||||
/// ```rust
|
||||
/// # use std::fmt::Write;
|
||||
/// # let mut buf = String::new();
|
||||
/// # let something = "something";
|
||||
/// writeln!(buf, "string to write: {}", something);
|
||||
/// ```
|
||||
/// will return
|
||||
/// ```rust,ignore
|
||||
/// (Some("string to write: {}"), Some(buf))
|
||||
/// ```
|
||||
fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option<StrLit>, Option<Expr>) {
|
||||
let mut parser = parser::Parser::new(&cx.sess().parse_sess, tts, false, None);
|
||||
let expr = if is_write {
|
||||
match parser
|
||||
.parse_expr()
|
||||
.map(rustc_ast::ptr::P::into_inner)
|
||||
.map_err(DiagnosticBuilder::cancel)
|
||||
{
|
||||
// write!(e, ...)
|
||||
Ok(p) if parser.eat(&token::Comma) => Some(p),
|
||||
// write!(e) or error
|
||||
e => return (None, e.ok()),
|
||||
}
|
||||
WRITELN_EMPTY_STRING
|
||||
} else {
|
||||
None
|
||||
PRINTLN_EMPTY_STRING
|
||||
};
|
||||
|
||||
let fmtstr = match parser.parse_str_lit() {
|
||||
Ok(fmtstr) => fmtstr,
|
||||
Err(_) => return (None, expr),
|
||||
};
|
||||
|
||||
let args = match self.parse_fmt_string(cx, &fmtstr) {
|
||||
Some(args) => args,
|
||||
None => return (Some(fmtstr), expr),
|
||||
};
|
||||
|
||||
let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL };
|
||||
let mut unnamed_args = args.get_unnamed();
|
||||
let mut complex_unnamed_args = args.get_complex_unnamed();
|
||||
loop {
|
||||
if !parser.eat(&token::Comma) {
|
||||
return (Some(fmtstr), expr);
|
||||
}
|
||||
|
||||
let comma_span = parser.prev_token.span;
|
||||
let token_expr = if let Ok(expr) = parser.parse_expr().map_err(DiagnosticBuilder::cancel) {
|
||||
expr
|
||||
} else {
|
||||
return (Some(fmtstr), None);
|
||||
};
|
||||
let complex_unnamed_arg = complex_unnamed_args.next();
|
||||
|
||||
let (fmt_spans, lit) = match &token_expr.kind {
|
||||
ExprKind::Lit(lit) => (unnamed_args.next().unwrap_or(&[]), lit),
|
||||
ExprKind::Assign(lhs, rhs, _) => {
|
||||
if let Some(span) = complex_unnamed_arg {
|
||||
for x in span {
|
||||
Self::report_positional_named_param(cx, *x, lhs, rhs);
|
||||
}
|
||||
}
|
||||
match (&lhs.kind, &rhs.kind) {
|
||||
(ExprKind::Path(_, p), ExprKind::Lit(lit)) => (args.get_named(p), lit),
|
||||
_ => continue,
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
unnamed_args.next();
|
||||
continue;
|
||||
},
|
||||
};
|
||||
|
||||
let replacement: String = match lit.token_lit.kind {
|
||||
LitKind::StrRaw(_) | LitKind::ByteStrRaw(_) if matches!(fmtstr.style, StrStyle::Raw(_)) => {
|
||||
lit.token_lit.symbol.as_str().replace('{', "{{").replace('}', "}}")
|
||||
},
|
||||
LitKind::Str | LitKind::ByteStr if matches!(fmtstr.style, StrStyle::Cooked) => {
|
||||
lit.token_lit.symbol.as_str().replace('{', "{{").replace('}', "}}")
|
||||
},
|
||||
LitKind::StrRaw(_)
|
||||
| LitKind::Str
|
||||
| LitKind::ByteStrRaw(_)
|
||||
| LitKind::ByteStr
|
||||
| LitKind::Integer
|
||||
| LitKind::Float
|
||||
| LitKind::Err => continue,
|
||||
LitKind::Byte | LitKind::Char => match lit.token_lit.symbol.as_str() {
|
||||
"\"" if matches!(fmtstr.style, StrStyle::Cooked) => "\\\"",
|
||||
"\"" if matches!(fmtstr.style, StrStyle::Raw(0)) => continue,
|
||||
"\\\\" if matches!(fmtstr.style, StrStyle::Raw(_)) => "\\",
|
||||
"\\'" => "'",
|
||||
"{" => "{{",
|
||||
"}" => "}}",
|
||||
x if matches!(fmtstr.style, StrStyle::Raw(_)) && x.starts_with('\\') => continue,
|
||||
x => x,
|
||||
}
|
||||
.into(),
|
||||
LitKind::Bool => lit.token_lit.symbol.as_str().deref().into(),
|
||||
};
|
||||
|
||||
if !fmt_spans.is_empty() {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
lint,
|
||||
token_expr.span,
|
||||
"literal with an empty format string",
|
||||
|diag| {
|
||||
diag.multipart_suggestion(
|
||||
"try this",
|
||||
iter::once((comma_span.to(token_expr.span), String::new()))
|
||||
.chain(fmt_spans.iter().copied().zip(iter::repeat(replacement)))
|
||||
.collect(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn report_positional_named_param(cx: &EarlyContext<'_>, span: Span, lhs: &P<Expr>, _rhs: &P<Expr>) {
|
||||
if let ExprKind::Path(_, _p) = &lhs.kind {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let name = snippet_with_applicability(cx, lhs.span, "name", &mut applicability);
|
||||
// We need to do this hack as precision spans should be converted from .* to .foo$
|
||||
let hack = snippet(cx, span, "").contains('*');
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
POSITIONAL_NAMED_FORMAT_PARAMETERS,
|
||||
span,
|
||||
&format!("named parameter {} is used as a positional parameter", name),
|
||||
"replace it with",
|
||||
if hack {
|
||||
format!("{}$", name)
|
||||
} else {
|
||||
format!("{}", name)
|
||||
},
|
||||
applicability,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
fn lint_println_empty_string(&self, cx: &EarlyContext<'_>, mac: &MacCall) {
|
||||
if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
|
||||
if fmt_str.symbol == kw::Empty {
|
||||
let name = mac.path.segments[0].ident.name;
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
PRINTLN_EMPTY_STRING,
|
||||
mac.span(),
|
||||
&format!("using `{}!(\"\")`", name),
|
||||
"replace it with",
|
||||
format!("{}!()", name),
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
lint,
|
||||
macro_call.span,
|
||||
&format!("empty string literal in `{name}!`"),
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"remove the empty string",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, name: &str) {
|
||||
let mut counts = HirIdMap::<usize>::default();
|
||||
for param in format_args.params() {
|
||||
*counts.entry(param.value.hir_id).or_default() += 1;
|
||||
}
|
||||
|
||||
fn lint_print_with_newline(&self, cx: &EarlyContext<'_>, mac: &MacCall) {
|
||||
if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
|
||||
if check_newlines(&fmt_str) {
|
||||
let name = mac.path.segments[0].ident.name;
|
||||
let suggested = format!("{}ln", name);
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
PRINT_WITH_NEWLINE,
|
||||
mac.span(),
|
||||
&format!("using `{}!()` with a format string that ends in a single newline", name),
|
||||
|err| {
|
||||
err.multipart_suggestion(
|
||||
&format!("use `{}!` instead", suggested),
|
||||
vec![(mac.path.span, suggested), (newline_span(&fmt_str).0, String::new())],
|
||||
for arg in &format_args.args {
|
||||
let value = arg.param.value;
|
||||
|
||||
if counts[&value.hir_id] == 1
|
||||
&& arg.format.is_default()
|
||||
&& let ExprKind::Lit(lit) = &value.kind
|
||||
&& !value.span.from_expansion()
|
||||
&& let Some(value_string) = snippet_opt(cx, value.span)
|
||||
{
|
||||
let (replacement, replace_raw) = match lit.node {
|
||||
LitKind::Str(..) => extract_str_literal(&value_string),
|
||||
LitKind::Char(ch) => (
|
||||
match ch {
|
||||
'"' => "\\\"",
|
||||
'\'' => "'",
|
||||
_ => &value_string[1..value_string.len() - 1],
|
||||
}
|
||||
.to_string(),
|
||||
false,
|
||||
),
|
||||
LitKind::Bool(b) => (b.to_string(), false),
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let lint = if name.starts_with("write") {
|
||||
WRITE_LITERAL
|
||||
} else {
|
||||
PRINT_LITERAL
|
||||
};
|
||||
|
||||
let format_string_is_raw = format_args.format_string.style.is_some();
|
||||
let replacement = match (format_string_is_raw, replace_raw) {
|
||||
(false, false) => Some(replacement),
|
||||
(false, true) => Some(replacement.replace('"', "\\\"").replace('\\', "\\\\")),
|
||||
(true, false) => match conservative_unescape(&replacement) {
|
||||
Ok(unescaped) => Some(unescaped),
|
||||
Err(UnescapeErr::Lint) => None,
|
||||
Err(UnescapeErr::Ignore) => continue,
|
||||
},
|
||||
(true, true) => {
|
||||
if replacement.contains(['#', '"']) {
|
||||
None
|
||||
} else {
|
||||
Some(replacement)
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
lint,
|
||||
value.span,
|
||||
"literal with an empty format string",
|
||||
|diag| {
|
||||
if let Some(replacement) = replacement {
|
||||
// `format!("{}", "a")`, `format!("{named}", named = "b")
|
||||
// ~~~~~ ~~~~~~~~~~~~~
|
||||
let value_span = expand_past_previous_comma(cx, value.span);
|
||||
|
||||
let replacement = replacement.replace('{', "{{").replace('}', "}}");
|
||||
diag.multipart_suggestion(
|
||||
"try this",
|
||||
vec![(arg.span, replacement), (value_span, String::new())],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the format string contains a single newline that terminates it.
|
||||
/// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw
|
||||
///
|
||||
/// Literal and escaped newlines are both checked (only literal for raw strings).
|
||||
fn check_newlines(fmtstr: &StrLit) -> bool {
|
||||
let mut has_internal_newline = false;
|
||||
let mut last_was_cr = false;
|
||||
let mut should_lint = false;
|
||||
|
||||
let contents = fmtstr.symbol.as_str();
|
||||
|
||||
let mut cb = |r: Range<usize>, c: Result<char, EscapeError>| {
|
||||
let c = match c {
|
||||
Ok(c) => c,
|
||||
Err(e) if !e.is_fatal() => return,
|
||||
Err(e) => panic!("{:?}", e),
|
||||
};
|
||||
|
||||
if r.end == contents.len() && c == '\n' && !last_was_cr && !has_internal_newline {
|
||||
should_lint = true;
|
||||
} else {
|
||||
last_was_cr = c == '\r';
|
||||
if c == '\n' {
|
||||
has_internal_newline = true;
|
||||
}
|
||||
}
|
||||
/// `r#"a"#` -> (`a`, true)
|
||||
///
|
||||
/// `"b"` -> (`b`, false)
|
||||
fn extract_str_literal(literal: &str) -> (String, bool) {
|
||||
let (literal, raw) = match literal.strip_prefix('r') {
|
||||
Some(stripped) => (stripped.trim_matches('#'), true),
|
||||
None => (literal, false),
|
||||
};
|
||||
|
||||
match fmtstr.style {
|
||||
StrStyle::Cooked => unescape::unescape_literal(contents, unescape::Mode::Str, &mut cb),
|
||||
StrStyle::Raw(_) => unescape::unescape_literal(contents, unescape::Mode::RawStr, &mut cb),
|
||||
(literal[1..literal.len() - 1].to_string(), raw)
|
||||
}
|
||||
|
||||
enum UnescapeErr {
|
||||
/// Should still be linted, can be manually resolved by author, e.g.
|
||||
///
|
||||
/// ```ignore
|
||||
/// print!(r"{}", '"');
|
||||
/// ```
|
||||
Lint,
|
||||
/// Should not be linted, e.g.
|
||||
///
|
||||
/// ```ignore
|
||||
/// print!(r"{}", '\r');
|
||||
/// ```
|
||||
Ignore,
|
||||
}
|
||||
|
||||
/// Unescape a normal string into a raw string
|
||||
fn conservative_unescape(literal: &str) -> Result<String, UnescapeErr> {
|
||||
let mut unescaped = String::with_capacity(literal.len());
|
||||
let mut chars = literal.chars();
|
||||
let mut err = false;
|
||||
|
||||
while let Some(ch) = chars.next() {
|
||||
match ch {
|
||||
'#' => err = true,
|
||||
'\\' => match chars.next() {
|
||||
Some('\\') => unescaped.push('\\'),
|
||||
Some('"') => err = true,
|
||||
_ => return Err(UnescapeErr::Ignore),
|
||||
},
|
||||
_ => unescaped.push(ch),
|
||||
}
|
||||
}
|
||||
|
||||
should_lint
|
||||
if err { Err(UnescapeErr::Lint) } else { Ok(unescaped) }
|
||||
}
|
||||
|
||||
// Expand from `writeln!(o, "")` to `writeln!(o, "")`
|
||||
// ^^ ^^^^
|
||||
fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span {
|
||||
let extended = cx.sess().source_map().span_extend_to_prev_char(span, ',', true);
|
||||
extended.with_lo(extended.lo() - BytePos(1))
|
||||
}
|
||||
|
|
|
@ -501,8 +501,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||
BinOpKind::Mul => l.checked_mul(r).map(zext),
|
||||
BinOpKind::Div if r != 0 => l.checked_div(r).map(zext),
|
||||
BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext),
|
||||
BinOpKind::Shr => l.checked_shr(r.try_into().expect("invalid shift")).map(zext),
|
||||
BinOpKind::Shl => l.checked_shl(r.try_into().expect("invalid shift")).map(zext),
|
||||
BinOpKind::Shr => l.checked_shr(r.try_into().ok()?).map(zext),
|
||||
BinOpKind::Shl => l.checked_shl(r.try_into().ok()?).map(zext),
|
||||
BinOpKind::BitXor => Some(zext(l ^ r)),
|
||||
BinOpKind::BitOr => Some(zext(l | r)),
|
||||
BinOpKind::BitAnd => Some(zext(l & r)),
|
||||
|
@ -521,8 +521,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||
BinOpKind::Mul => l.checked_mul(r).map(Constant::Int),
|
||||
BinOpKind::Div => l.checked_div(r).map(Constant::Int),
|
||||
BinOpKind::Rem => l.checked_rem(r).map(Constant::Int),
|
||||
BinOpKind::Shr => l.checked_shr(r.try_into().expect("shift too large")).map(Constant::Int),
|
||||
BinOpKind::Shl => l.checked_shl(r.try_into().expect("shift too large")).map(Constant::Int),
|
||||
BinOpKind::Shr => l.checked_shr(r.try_into().ok()?).map(Constant::Int),
|
||||
BinOpKind::Shl => l.checked_shl(r.try_into().ok()?).map(Constant::Int),
|
||||
BinOpKind::BitXor => Some(Constant::Int(l ^ r)),
|
||||
BinOpKind::BitOr => Some(Constant::Int(l | r)),
|
||||
BinOpKind::BitAnd => Some(Constant::Int(l & r)),
|
||||
|
|
|
@ -7,8 +7,8 @@ use crate::visitors::expr_visitor_no_bodies;
|
|||
use arrayvec::ArrayVec;
|
||||
use itertools::{izip, Either, Itertools};
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath};
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, Node, QPath};
|
||||
use rustc_lexer::unescape::unescape_literal;
|
||||
use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
@ -485,64 +485,49 @@ struct ParamPosition {
|
|||
precision: Option<usize>,
|
||||
}
|
||||
|
||||
/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)`
|
||||
fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option<impl Iterator<Item = ParamPosition> + 'tcx> {
|
||||
fn parse_count(expr: &Expr<'_>) -> Option<usize> {
|
||||
// ::core::fmt::rt::v1::Count::Param(1usize),
|
||||
if let ExprKind::Call(ctor, [val]) = expr.kind
|
||||
&& let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind
|
||||
&& path.segments.last()?.ident.name == sym::Param
|
||||
&& let ExprKind::Lit(lit) = &val.kind
|
||||
&& let LitKind::Int(pos, _) = lit.node
|
||||
{
|
||||
Some(pos as usize)
|
||||
} else {
|
||||
None
|
||||
impl<'tcx> Visitor<'tcx> for ParamPosition {
|
||||
fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) {
|
||||
fn parse_count(expr: &Expr<'_>) -> Option<usize> {
|
||||
// ::core::fmt::rt::v1::Count::Param(1usize),
|
||||
if let ExprKind::Call(ctor, [val]) = expr.kind
|
||||
&& let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind
|
||||
&& path.segments.last()?.ident.name == sym::Param
|
||||
&& let ExprKind::Lit(lit) = &val.kind
|
||||
&& let LitKind::Int(pos, _) = lit.node
|
||||
{
|
||||
Some(pos as usize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
match field.ident.name {
|
||||
sym::position => {
|
||||
if let ExprKind::Lit(lit) = &field.expr.kind
|
||||
&& let LitKind::Int(pos, _) = lit.node
|
||||
{
|
||||
self.value = pos as usize;
|
||||
}
|
||||
},
|
||||
sym::precision => {
|
||||
self.precision = parse_count(field.expr);
|
||||
},
|
||||
sym::width => {
|
||||
self.width = parse_count(field.expr);
|
||||
},
|
||||
_ => walk_expr(self, field.expr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)`
|
||||
fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option<impl Iterator<Item = ParamPosition> + 'tcx> {
|
||||
if let ExprKind::AddrOf(.., array) = fmt_arg.kind
|
||||
&& let ExprKind::Array(specs) = array.kind
|
||||
{
|
||||
Some(specs.iter().map(|spec| {
|
||||
let mut position = ParamPosition::default();
|
||||
|
||||
// ::core::fmt::rt::v1::Argument {
|
||||
// position: 0usize,
|
||||
// format: ::core::fmt::rt::v1::FormatSpec {
|
||||
// ..
|
||||
// precision: ::core::fmt::rt::v1::Count::Implied,
|
||||
// width: ::core::fmt::rt::v1::Count::Implied,
|
||||
// },
|
||||
// }
|
||||
|
||||
// TODO: this can be made much nicer next sync with `Visitor::visit_expr_field`
|
||||
if let ExprKind::Struct(_, fields, _) = spec.kind {
|
||||
for field in fields {
|
||||
match (field.ident.name, &field.expr.kind) {
|
||||
(sym::position, ExprKind::Lit(lit)) => {
|
||||
if let LitKind::Int(pos, _) = lit.node {
|
||||
position.value = pos as usize;
|
||||
}
|
||||
},
|
||||
(sym::format, &ExprKind::Struct(_, spec_fields, _)) => {
|
||||
for spec_field in spec_fields {
|
||||
match spec_field.ident.name {
|
||||
sym::precision => {
|
||||
position.precision = parse_count(spec_field.expr);
|
||||
},
|
||||
sym::width => {
|
||||
position.width = parse_count(spec_field.expr);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
position.visit_expr(spec);
|
||||
position
|
||||
}))
|
||||
} else {
|
||||
|
@ -711,9 +696,14 @@ impl<'tcx> FormatSpec<'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Returns true if this format spec would change the contents of a string when formatted
|
||||
pub fn has_string_formatting(&self) -> bool {
|
||||
self.r#trait != sym::Display || !self.width.is_implied() || !self.precision.is_implied()
|
||||
/// Returns true if this format spec is unchanged from the default. e.g. returns true for `{}`,
|
||||
/// `{foo}` and `{2}`, but false for `{:?}`, `{foo:5}` and `{3:.5}`
|
||||
pub fn is_default(&self) -> bool {
|
||||
self.r#trait == sym::Display
|
||||
&& self.width.is_implied()
|
||||
&& self.precision.is_implied()
|
||||
&& self.align == Alignment::AlignUnknown
|
||||
&& self.flags == 0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ use std::fmt::{Display, Write as _};
|
|||
use std::ops::{Add, Neg, Not, Sub};
|
||||
|
||||
/// A helper type to build suggestion correctly handling parentheses.
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Sugg<'a> {
|
||||
/// An expression that never needs parentheses such as `1337` or `[0; 42]`.
|
||||
NonParen(Cow<'a, str>),
|
||||
|
@ -155,8 +155,8 @@ impl<'a> Sugg<'a> {
|
|||
| hir::ExprKind::Ret(..)
|
||||
| hir::ExprKind::Struct(..)
|
||||
| hir::ExprKind::Tup(..)
|
||||
| hir::ExprKind::DropTemps(_)
|
||||
| hir::ExprKind::Err => Sugg::NonParen(get_snippet(expr.span)),
|
||||
hir::ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet),
|
||||
hir::ExprKind::Assign(lhs, rhs, _) => {
|
||||
Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span))
|
||||
},
|
||||
|
@ -177,11 +177,11 @@ impl<'a> Sugg<'a> {
|
|||
pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
|
||||
use rustc_ast::ast::RangeLimits;
|
||||
|
||||
let get_whole_snippet = || {
|
||||
if expr.span.from_expansion() {
|
||||
snippet_with_macro_callsite(cx, expr.span, default)
|
||||
let snippet_without_expansion = |cx, span: Span, default| {
|
||||
if span.from_expansion() {
|
||||
snippet_with_macro_callsite(cx, span, default)
|
||||
} else {
|
||||
snippet(cx, expr.span, default)
|
||||
snippet(cx, span, default)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -192,7 +192,7 @@ impl<'a> Sugg<'a> {
|
|||
| ast::ExprKind::If(..)
|
||||
| ast::ExprKind::Let(..)
|
||||
| ast::ExprKind::Unary(..)
|
||||
| ast::ExprKind::Match(..) => Sugg::MaybeParen(get_whole_snippet()),
|
||||
| ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet_without_expansion(cx, expr.span, default)),
|
||||
ast::ExprKind::Async(..)
|
||||
| ast::ExprKind::Block(..)
|
||||
| ast::ExprKind::Break(..)
|
||||
|
@ -221,41 +221,45 @@ impl<'a> Sugg<'a> {
|
|||
| ast::ExprKind::Array(..)
|
||||
| ast::ExprKind::While(..)
|
||||
| ast::ExprKind::Await(..)
|
||||
| ast::ExprKind::Err => Sugg::NonParen(get_whole_snippet()),
|
||||
| ast::ExprKind::Err => Sugg::NonParen(snippet_without_expansion(cx, expr.span, default)),
|
||||
ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp(
|
||||
AssocOp::DotDot,
|
||||
lhs.as_ref().map_or("".into(), |lhs| snippet(cx, lhs.span, default)),
|
||||
rhs.as_ref().map_or("".into(), |rhs| snippet(cx, rhs.span, default)),
|
||||
lhs.as_ref()
|
||||
.map_or("".into(), |lhs| snippet_without_expansion(cx, lhs.span, default)),
|
||||
rhs.as_ref()
|
||||
.map_or("".into(), |rhs| snippet_without_expansion(cx, rhs.span, default)),
|
||||
),
|
||||
ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp(
|
||||
AssocOp::DotDotEq,
|
||||
lhs.as_ref().map_or("".into(), |lhs| snippet(cx, lhs.span, default)),
|
||||
rhs.as_ref().map_or("".into(), |rhs| snippet(cx, rhs.span, default)),
|
||||
lhs.as_ref()
|
||||
.map_or("".into(), |lhs| snippet_without_expansion(cx, lhs.span, default)),
|
||||
rhs.as_ref()
|
||||
.map_or("".into(), |rhs| snippet_without_expansion(cx, rhs.span, default)),
|
||||
),
|
||||
ast::ExprKind::Assign(ref lhs, ref rhs, _) => Sugg::BinOp(
|
||||
AssocOp::Assign,
|
||||
snippet(cx, lhs.span, default),
|
||||
snippet(cx, rhs.span, default),
|
||||
snippet_without_expansion(cx, lhs.span, default),
|
||||
snippet_without_expansion(cx, rhs.span, default),
|
||||
),
|
||||
ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp(
|
||||
astbinop2assignop(op),
|
||||
snippet(cx, lhs.span, default),
|
||||
snippet(cx, rhs.span, default),
|
||||
snippet_without_expansion(cx, lhs.span, default),
|
||||
snippet_without_expansion(cx, rhs.span, default),
|
||||
),
|
||||
ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp(
|
||||
AssocOp::from_ast_binop(op.node),
|
||||
snippet(cx, lhs.span, default),
|
||||
snippet(cx, rhs.span, default),
|
||||
snippet_without_expansion(cx, lhs.span, default),
|
||||
snippet_without_expansion(cx, rhs.span, default),
|
||||
),
|
||||
ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp(
|
||||
AssocOp::As,
|
||||
snippet(cx, lhs.span, default),
|
||||
snippet(cx, ty.span, default),
|
||||
snippet_without_expansion(cx, lhs.span, default),
|
||||
snippet_without_expansion(cx, ty.span, default),
|
||||
),
|
||||
ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp(
|
||||
AssocOp::Colon,
|
||||
snippet(cx, lhs.span, default),
|
||||
snippet(cx, ty.span, default),
|
||||
snippet_without_expansion(cx, lhs.span, default),
|
||||
snippet_without_expansion(cx, ty.span, default),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,13 @@ pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env)
|
||||
}
|
||||
|
||||
/// This checks whether a given type is known to implement Debug.
|
||||
pub fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
cx.tcx
|
||||
.get_diagnostic_item(sym::Debug)
|
||||
.map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
|
||||
}
|
||||
|
||||
/// Checks whether a type can be partially moved.
|
||||
pub fn can_partially_move_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
if has_drop(cx, ty) || is_copy(cx, ty) {
|
||||
|
|
|
@ -221,6 +221,7 @@ docs! {
|
|||
"items_after_statements",
|
||||
"iter_cloned_collect",
|
||||
"iter_count",
|
||||
"iter_kv_map",
|
||||
"iter_next_loop",
|
||||
"iter_next_slice",
|
||||
"iter_not_returning_iterator",
|
||||
|
@ -391,7 +392,6 @@ docs! {
|
|||
"partialeq_to_none",
|
||||
"path_buf_push_overwrite",
|
||||
"pattern_type_mismatch",
|
||||
"positional_named_format_parameters",
|
||||
"possible_missing_comma",
|
||||
"precedence",
|
||||
"print_in_format_impl",
|
||||
|
|
22
src/docs/iter_kv_map.txt
Normal file
22
src/docs/iter_kv_map.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
### What it does
|
||||
|
||||
Checks for iterating a map (`HashMap` or `BTreeMap`) and
|
||||
ignoring either the keys or values.
|
||||
|
||||
### Why is this bad?
|
||||
|
||||
Readability. There are `keys` and `values` methods that
|
||||
can be used to express that we only need the keys or the values.
|
||||
|
||||
### Example
|
||||
|
||||
```
|
||||
let map: HashMap<u32, u32> = HashMap::new();
|
||||
let values = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
|
||||
```
|
||||
|
||||
Use instead:
|
||||
```
|
||||
let map: HashMap<u32, u32> = HashMap::new();
|
||||
let values = map.values().collect::<Vec<_>>();
|
||||
```
|
|
@ -1,15 +0,0 @@
|
|||
### What it does
|
||||
This lint warns when a named parameter in a format string is used as a positional one.
|
||||
|
||||
### Why is this bad?
|
||||
It may be confused for an assignment and obfuscates which parameter is being used.
|
||||
|
||||
### Example
|
||||
```
|
||||
println!("{}", x = 10);
|
||||
```
|
||||
|
||||
Use instead:
|
||||
```
|
||||
println!("{x}", x = 10);
|
||||
```
|
|
@ -6,10 +6,6 @@ Using literals as `println!` args is inefficient
|
|||
(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
|
||||
(i.e., just put the literal in the format string)
|
||||
|
||||
### Known problems
|
||||
Will also warn with macro calls as arguments that expand to literals
|
||||
-- e.g., `println!("{}", env!("FOO"))`.
|
||||
|
||||
### Example
|
||||
```
|
||||
println!("{}", "foo");
|
||||
|
|
|
@ -7,13 +7,7 @@ People often print on *stderr* while debugging an
|
|||
application and might forget to remove those prints afterward.
|
||||
|
||||
### Known problems
|
||||
* Only catches `eprint!` and `eprintln!` calls.
|
||||
* The lint level is unaffected by crate attributes. The level can still
|
||||
be set for functions, modules and other items. To change the level for
|
||||
the entire crate, please use command line flags. More information and a
|
||||
configuration example can be found in [clippy#6610].
|
||||
|
||||
[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
|
||||
Only catches `eprint!` and `eprintln!` calls.
|
||||
|
||||
### Example
|
||||
```
|
||||
|
|
|
@ -7,13 +7,7 @@ People often print on *stdout* while debugging an
|
|||
application and might forget to remove those prints afterward.
|
||||
|
||||
### Known problems
|
||||
* Only catches `print!` and `println!` calls.
|
||||
* The lint level is unaffected by crate attributes. The level can still
|
||||
be set for functions, modules and other items. To change the level for
|
||||
the entire crate, please use command line flags. More information and a
|
||||
configuration example can be found in [clippy#6610].
|
||||
|
||||
[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
|
||||
Only catches `print!` and `println!` calls.
|
||||
|
||||
### Example
|
||||
```
|
||||
|
|
|
@ -6,10 +6,6 @@ Using literals as `writeln!` args is inefficient
|
|||
(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
|
||||
(i.e., just put the literal in the format string)
|
||||
|
||||
### Known problems
|
||||
Will also warn with macro calls as arguments that expand to literals
|
||||
-- e.g., `writeln!(buf, "{}", env!("FOO"))`.
|
||||
|
||||
### Example
|
||||
```
|
||||
writeln!(buf, "{}", "foo");
|
||||
|
|
9
tests/ui-cargo/module_style/fail_mod_remap/Cargo.toml
Normal file
9
tests/ui-cargo/module_style/fail_mod_remap/Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "fail-mod-remap"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
1
tests/ui-cargo/module_style/fail_mod_remap/src/bad.rs
Normal file
1
tests/ui-cargo/module_style/fail_mod_remap/src/bad.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod inner;
|
|
@ -0,0 +1 @@
|
|||
|
7
tests/ui-cargo/module_style/fail_mod_remap/src/main.rs
Normal file
7
tests/ui-cargo/module_style/fail_mod_remap/src/main.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
// compile-flags: --remap-path-prefix {{src-base}}=/remapped
|
||||
|
||||
#![warn(clippy::self_named_module_files)]
|
||||
|
||||
mod bad;
|
||||
|
||||
fn main() {}
|
11
tests/ui-cargo/module_style/fail_mod_remap/src/main.stderr
Normal file
11
tests/ui-cargo/module_style/fail_mod_remap/src/main.stderr
Normal file
|
@ -0,0 +1,11 @@
|
|||
error: `mod.rs` files are required, found `bad.rs`
|
||||
--> /remapped/module_style/fail_mod_remap/src/bad.rs:1:1
|
||||
|
|
||||
LL | pub mod inner;
|
||||
| ^
|
||||
|
|
||||
= note: `-D clippy::self-named-module-files` implied by `-D warnings`
|
||||
= help: move `bad.rs` to `bad/mod.rs`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -42,6 +42,7 @@ macro_rules! printlnfoo {
|
|||
fn main() {
|
||||
let _ = vec! {1, 2, 3};
|
||||
let _ = format!["ugh {} stop being such a good compiler", "hello"];
|
||||
let _ = matches!{{}, ()};
|
||||
let _ = quote!(let x = 1;);
|
||||
let _ = quote::quote!(match match match);
|
||||
let _ = test!(); // trigger when macro def is inside our own crate
|
||||
|
|
|
@ -23,26 +23,38 @@ help: consider writing `format!("ugh () stop being such a good compiler", "hello
|
|||
LL | let _ = format!["ugh {} stop being such a good compiler", "hello"];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of irregular braces for `quote!` macro
|
||||
error: use of irregular braces for `matches!` macro
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:45:13
|
||||
|
|
||||
LL | let _ = matches!{{}, ()};
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider writing `matches!((), ())`
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:45:13
|
||||
|
|
||||
LL | let _ = matches!{{}, ()};
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of irregular braces for `quote!` macro
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:46:13
|
||||
|
|
||||
LL | let _ = quote!(let x = 1;);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider writing `quote! {let x = 1;}`
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:45:13
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:46:13
|
||||
|
|
||||
LL | let _ = quote!(let x = 1;);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of irregular braces for `quote::quote!` macro
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:46:13
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:47:13
|
||||
|
|
||||
LL | let _ = quote::quote!(match match match);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider writing `quote::quote! {match match match}`
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:46:13
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:47:13
|
||||
|
|
||||
LL | let _ = quote::quote!(match match match);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -67,28 +79,28 @@ LL | let _ = test!(); // trigger when macro def is inside our own crate
|
|||
= note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: use of irregular braces for `type_pos!` macro
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:55:12
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:56:12
|
||||
|
|
||||
LL | let _: type_pos!(usize) = vec![];
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider writing `type_pos![usize]`
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:55:12
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:56:12
|
||||
|
|
||||
LL | let _: type_pos!(usize) = vec![];
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of irregular braces for `eprint!` macro
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:57:5
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:58:5
|
||||
|
|
||||
LL | eprint!("test if user config overrides defaults");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider writing `eprint!["test if user config overrides defaults"]`
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:57:5
|
||||
--> $DIR/conf_nonstandard_macro_braces.rs:58:5
|
||||
|
|
||||
LL | eprint!("test if user config overrides defaults");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-rustfix
|
||||
// edition:2018
|
||||
// aux-build:macro_rules.rs
|
||||
|
||||
#![feature(custom_inner_attributes)]
|
||||
#![feature(exclusive_range_pattern)]
|
||||
|
@ -8,12 +9,21 @@
|
|||
#![allow(ellipsis_inclusive_range_patterns)]
|
||||
#![allow(clippy::needless_parens_on_range_literals)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate macro_rules;
|
||||
|
||||
macro_rules! a {
|
||||
() => {
|
||||
'a'
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! b {
|
||||
() => {
|
||||
let _ = 'a'..='z';
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[rustfmt::skip]
|
||||
{
|
||||
|
@ -47,6 +57,9 @@ fn main() {
|
|||
'B'..'Z' => 4,
|
||||
_ => 5,
|
||||
};
|
||||
|
||||
almost_complete_letter_range!();
|
||||
b!();
|
||||
}
|
||||
|
||||
fn _under_msrv() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-rustfix
|
||||
// edition:2018
|
||||
// aux-build:macro_rules.rs
|
||||
|
||||
#![feature(custom_inner_attributes)]
|
||||
#![feature(exclusive_range_pattern)]
|
||||
|
@ -8,12 +9,21 @@
|
|||
#![allow(ellipsis_inclusive_range_patterns)]
|
||||
#![allow(clippy::needless_parens_on_range_literals)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate macro_rules;
|
||||
|
||||
macro_rules! a {
|
||||
() => {
|
||||
'a'
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! b {
|
||||
() => {
|
||||
let _ = 'a'..'z';
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[rustfmt::skip]
|
||||
{
|
||||
|
@ -47,6 +57,9 @@ fn main() {
|
|||
'B'..'Z' => 4,
|
||||
_ => 5,
|
||||
};
|
||||
|
||||
almost_complete_letter_range!();
|
||||
b!();
|
||||
}
|
||||
|
||||
fn _under_msrv() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:20:17
|
||||
--> $DIR/almost_complete_letter_range.rs:30:17
|
||||
|
|
||||
LL | let _ = ('a') ..'z';
|
||||
| ^^^^^^--^^^
|
||||
|
@ -9,7 +9,7 @@ LL | let _ = ('a') ..'z';
|
|||
= note: `-D clippy::almost-complete-letter-range` implied by `-D warnings`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:21:17
|
||||
--> $DIR/almost_complete_letter_range.rs:31:17
|
||||
|
|
||||
LL | let _ = 'A' .. ('Z');
|
||||
| ^^^^--^^^^^^
|
||||
|
@ -17,7 +17,7 @@ LL | let _ = 'A' .. ('Z');
|
|||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:27:13
|
||||
--> $DIR/almost_complete_letter_range.rs:37:13
|
||||
|
|
||||
LL | let _ = (b'a')..(b'z');
|
||||
| ^^^^^^--^^^^^^
|
||||
|
@ -25,7 +25,7 @@ LL | let _ = (b'a')..(b'z');
|
|||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:28:13
|
||||
--> $DIR/almost_complete_letter_range.rs:38:13
|
||||
|
|
||||
LL | let _ = b'A'..b'Z';
|
||||
| ^^^^--^^^^
|
||||
|
@ -33,7 +33,7 @@ LL | let _ = b'A'..b'Z';
|
|||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:33:13
|
||||
--> $DIR/almost_complete_letter_range.rs:43:13
|
||||
|
|
||||
LL | let _ = a!()..'z';
|
||||
| ^^^^--^^^
|
||||
|
@ -41,7 +41,7 @@ LL | let _ = a!()..'z';
|
|||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:36:9
|
||||
--> $DIR/almost_complete_letter_range.rs:46:9
|
||||
|
|
||||
LL | b'a'..b'z' if true => 1,
|
||||
| ^^^^--^^^^
|
||||
|
@ -49,7 +49,7 @@ LL | b'a'..b'z' if true => 1,
|
|||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:37:9
|
||||
--> $DIR/almost_complete_letter_range.rs:47:9
|
||||
|
|
||||
LL | b'A'..b'Z' if true => 2,
|
||||
| ^^^^--^^^^
|
||||
|
@ -57,7 +57,7 @@ LL | b'A'..b'Z' if true => 2,
|
|||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:44:9
|
||||
--> $DIR/almost_complete_letter_range.rs:54:9
|
||||
|
|
||||
LL | 'a'..'z' if true => 1,
|
||||
| ^^^--^^^
|
||||
|
@ -65,7 +65,7 @@ LL | 'a'..'z' if true => 1,
|
|||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:45:9
|
||||
--> $DIR/almost_complete_letter_range.rs:55:9
|
||||
|
|
||||
LL | 'A'..'Z' if true => 2,
|
||||
| ^^^--^^^
|
||||
|
@ -73,7 +73,20 @@ LL | 'A'..'Z' if true => 2,
|
|||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:55:9
|
||||
--> $DIR/almost_complete_letter_range.rs:23:17
|
||||
|
|
||||
LL | let _ = 'a'..'z';
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
...
|
||||
LL | b!();
|
||||
| ---- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:68:9
|
||||
|
|
||||
LL | 'a'..'z' => 1,
|
||||
| ^^^--^^^
|
||||
|
@ -81,7 +94,7 @@ LL | 'a'..'z' => 1,
|
|||
| help: use an inclusive range: `...`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:62:13
|
||||
--> $DIR/almost_complete_letter_range.rs:75:13
|
||||
|
|
||||
LL | let _ = 'a'..'z';
|
||||
| ^^^--^^^
|
||||
|
@ -89,12 +102,12 @@ LL | let _ = 'a'..'z';
|
|||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: almost complete ascii letter range
|
||||
--> $DIR/almost_complete_letter_range.rs:64:9
|
||||
--> $DIR/almost_complete_letter_range.rs:77:9
|
||||
|
|
||||
LL | 'a'..'z' => 1,
|
||||
| ^^^--^^^
|
||||
| |
|
||||
| help: use an inclusive range: `..=`
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
|
|
|
@ -1,9 +1,49 @@
|
|||
#![allow(clippy::assign_op_pattern, clippy::unnecessary_owned_empty_strings)]
|
||||
#![allow(
|
||||
clippy::assign_op_pattern,
|
||||
clippy::erasing_op,
|
||||
clippy::identity_op,
|
||||
clippy::unnecessary_owned_empty_strings,
|
||||
arithmetic_overflow,
|
||||
unconditional_panic
|
||||
)]
|
||||
#![feature(inline_const, saturating_int_impl)]
|
||||
#![warn(clippy::arithmetic_side_effects)]
|
||||
|
||||
use core::num::{Saturating, Wrapping};
|
||||
|
||||
pub fn association_with_structures_should_not_trigger_the_lint() {
|
||||
enum Foo {
|
||||
Bar = -2,
|
||||
}
|
||||
|
||||
impl Trait for Foo {
|
||||
const ASSOC: i32 = {
|
||||
let _: [i32; 1 + 1];
|
||||
fn foo() {}
|
||||
1 + 1
|
||||
};
|
||||
}
|
||||
|
||||
struct Baz([i32; 1 + 1]);
|
||||
|
||||
trait Trait {
|
||||
const ASSOC: i32 = 1 + 1;
|
||||
}
|
||||
|
||||
type Alias = [i32; 1 + 1];
|
||||
|
||||
union Qux {
|
||||
field: [i32; 1 + 1],
|
||||
}
|
||||
|
||||
let _: [i32; 1 + 1] = [0, 0];
|
||||
|
||||
let _: [i32; 1 + 1] = {
|
||||
let a: [i32; 1 + 1] = [0, 0];
|
||||
a
|
||||
};
|
||||
}
|
||||
|
||||
pub fn hard_coded_allowed() {
|
||||
let _ = 1f32 + 1f32;
|
||||
let _ = 1f64 + 1f64;
|
||||
|
@ -26,7 +66,7 @@ pub fn hard_coded_allowed() {
|
|||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub fn non_overflowing_ops() {
|
||||
pub fn const_ops_should_not_trigger_the_lint() {
|
||||
const _: i32 = { let mut n = 1; n += 1; n };
|
||||
let _ = const { let mut n = 1; n += 1; n };
|
||||
|
||||
|
@ -37,21 +77,63 @@ pub fn non_overflowing_ops() {
|
|||
let _ = const { let mut n = 1; n = 1 + n; n };
|
||||
|
||||
const _: i32 = 1 + 1;
|
||||
let _ = 1 + 1;
|
||||
let _ = const { 1 + 1 };
|
||||
|
||||
let mut _a = 1;
|
||||
_a *= 1;
|
||||
_a /= 1;
|
||||
const _: i32 = { let mut n = -1; n = -(-1); n = -n; n };
|
||||
let _ = const { let mut n = -1; n = -(-1); n = -n; n };
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub fn overflowing_ops() {
|
||||
let mut _a = 1; _a += 1;
|
||||
pub fn non_overflowing_runtime_ops_or_ops_already_handled_by_the_compiler() {
|
||||
let mut _n = i32::MAX;
|
||||
|
||||
let mut _b = 1; _b = _b + 1;
|
||||
// Assign
|
||||
_n += 0;
|
||||
_n -= 0;
|
||||
_n /= 99;
|
||||
_n %= 99;
|
||||
_n *= 0;
|
||||
_n *= 1;
|
||||
|
||||
let mut _c = 1; _c = 1 + _c;
|
||||
// Binary
|
||||
_n = _n + 0;
|
||||
_n = 0 + _n;
|
||||
_n = _n - 0;
|
||||
_n = 0 - _n;
|
||||
_n = _n / 99;
|
||||
_n = _n % 99;
|
||||
_n = _n * 0;
|
||||
_n = 0 * _n;
|
||||
_n = _n * 1;
|
||||
_n = 1 * _n;
|
||||
_n = 23 + 85;
|
||||
|
||||
// Unary
|
||||
_n = -1;
|
||||
_n = -(-1);
|
||||
}
|
||||
|
||||
pub fn overflowing_runtime_ops() {
|
||||
let mut _n = i32::MAX;
|
||||
|
||||
// Assign
|
||||
_n += 1;
|
||||
_n -= 1;
|
||||
_n /= 0;
|
||||
_n %= 0;
|
||||
_n *= 2;
|
||||
|
||||
// Binary
|
||||
_n = _n + 1;
|
||||
_n = 1 + _n;
|
||||
_n = _n - 1;
|
||||
_n = 1 - _n;
|
||||
_n = _n / 0;
|
||||
_n = _n % 0;
|
||||
_n = _n * 2;
|
||||
_n = 2 * _n;
|
||||
|
||||
// Unary
|
||||
_n = -_n;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,22 +1,88 @@
|
|||
error: arithmetic detected
|
||||
--> $DIR/arithmetic_side_effects.rs:50:21
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:119:5
|
||||
|
|
||||
LL | let mut _a = 1; _a += 1;
|
||||
| ^^^^^^^
|
||||
LL | _n += 1;
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
|
||||
|
||||
error: arithmetic detected
|
||||
--> $DIR/arithmetic_side_effects.rs:52:26
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:120:5
|
||||
|
|
||||
LL | let mut _b = 1; _b = _b + 1;
|
||||
| ^^^^^^
|
||||
LL | _n -= 1;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic detected
|
||||
--> $DIR/arithmetic_side_effects.rs:54:26
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:121:5
|
||||
|
|
||||
LL | let mut _c = 1; _c = 1 + _c;
|
||||
| ^^^^^^
|
||||
LL | _n /= 0;
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:122:5
|
||||
|
|
||||
LL | _n %= 0;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:123:5
|
||||
|
|
||||
LL | _n *= 2;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:126:10
|
||||
|
|
||||
LL | _n = _n + 1;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:127:10
|
||||
|
|
||||
LL | _n = 1 + _n;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:128:10
|
||||
|
|
||||
LL | _n = _n - 1;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:129:10
|
||||
|
|
||||
LL | _n = 1 - _n;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:130:10
|
||||
|
|
||||
LL | _n = _n / 0;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:131:10
|
||||
|
|
||||
LL | _n = _n % 0;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:132:10
|
||||
|
|
||||
LL | _n = _n * 2;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:133:10
|
||||
|
|
||||
LL | _n = 2 * _n;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:136:10
|
||||
|
|
||||
LL | _n = -_n;
|
||||
| ^^^
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
|
|
@ -75,3 +75,9 @@ fn main() {
|
|||
let r: Result<Foo, Foo> = Err(Foo);
|
||||
assert!(r.is_err());
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn issue9450() {
|
||||
let res: Result<i32, i32> = Ok(1);
|
||||
res.unwrap_err();
|
||||
}
|
||||
|
|
|
@ -75,3 +75,9 @@ fn main() {
|
|||
let r: Result<Foo, Foo> = Err(Foo);
|
||||
assert!(r.is_err());
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn issue9450() {
|
||||
let res: Result<i32, i32> = Ok(1);
|
||||
assert!(res.is_err())
|
||||
}
|
||||
|
|
|
@ -36,5 +36,11 @@ error: called `assert!` with `Result::is_err`
|
|||
LL | assert!(r.is_err());
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: called `assert!` with `Result::is_err`
|
||||
--> $DIR/assertions_on_result_states.rs:82:5
|
||||
|
|
||||
LL | assert!(res.is_err())
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: replace with: `res.unwrap_err();`
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
|
|
@ -140,3 +140,10 @@ macro_rules! manual_rem_euclid {
|
|||
macro_rules! equatable_if_let {
|
||||
($a:ident) => {{ if let 2 = $a {} }};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! almost_complete_letter_range {
|
||||
() => {
|
||||
let _ = 'a'..'z';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ fn main() {
|
|||
// precedence
|
||||
i32::from(a);
|
||||
i32::from(!a);
|
||||
i32::from(!a);
|
||||
i32::from(a || b);
|
||||
i32::from(cond(a, b));
|
||||
i32::from(x + y < 4);
|
||||
|
@ -21,7 +22,12 @@ fn main() {
|
|||
// if else if
|
||||
if a {
|
||||
123
|
||||
} else {i32::from(b)};
|
||||
} else { i32::from(b) };
|
||||
|
||||
// if else if inverted
|
||||
if a {
|
||||
123
|
||||
} else { i32::from(!b) };
|
||||
|
||||
// Shouldn't lint
|
||||
|
||||
|
|
|
@ -17,6 +17,11 @@ fn main() {
|
|||
} else {
|
||||
0
|
||||
};
|
||||
if a {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
};
|
||||
if !a {
|
||||
1
|
||||
} else {
|
||||
|
@ -47,6 +52,15 @@ fn main() {
|
|||
0
|
||||
};
|
||||
|
||||
// if else if inverted
|
||||
if a {
|
||||
123
|
||||
} else if b {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
// Shouldn't lint
|
||||
|
||||
if a {
|
||||
|
|
|
@ -14,6 +14,18 @@ LL | | };
|
|||
error: boolean to int conversion using if
|
||||
--> $DIR/bool_to_int_with_if.rs:20:5
|
||||
|
|
||||
LL | / if a {
|
||||
LL | | 0
|
||||
LL | | } else {
|
||||
LL | | 1
|
||||
LL | | };
|
||||
| |_____^ help: replace with from: `i32::from(!a)`
|
||||
|
|
||||
= note: `!a as i32` or `(!a).into()` can also be valid options
|
||||
|
||||
error: boolean to int conversion using if
|
||||
--> $DIR/bool_to_int_with_if.rs:25:5
|
||||
|
|
||||
LL | / if !a {
|
||||
LL | | 1
|
||||
LL | | } else {
|
||||
|
@ -21,10 +33,10 @@ LL | | 0
|
|||
LL | | };
|
||||
| |_____^ help: replace with from: `i32::from(!a)`
|
||||
|
|
||||
= note: `!a as i32` or `!a.into()` can also be valid options
|
||||
= note: `!a as i32` or `(!a).into()` can also be valid options
|
||||
|
||||
error: boolean to int conversion using if
|
||||
--> $DIR/bool_to_int_with_if.rs:25:5
|
||||
--> $DIR/bool_to_int_with_if.rs:30:5
|
||||
|
|
||||
LL | / if a || b {
|
||||
LL | | 1
|
||||
|
@ -36,7 +48,7 @@ LL | | };
|
|||
= note: `(a || b) as i32` or `(a || b).into()` can also be valid options
|
||||
|
||||
error: boolean to int conversion using if
|
||||
--> $DIR/bool_to_int_with_if.rs:30:5
|
||||
--> $DIR/bool_to_int_with_if.rs:35:5
|
||||
|
|
||||
LL | / if cond(a, b) {
|
||||
LL | | 1
|
||||
|
@ -48,7 +60,7 @@ LL | | };
|
|||
= note: `cond(a, b) as i32` or `cond(a, b).into()` can also be valid options
|
||||
|
||||
error: boolean to int conversion using if
|
||||
--> $DIR/bool_to_int_with_if.rs:35:5
|
||||
--> $DIR/bool_to_int_with_if.rs:40:5
|
||||
|
|
||||
LL | / if x + y < 4 {
|
||||
LL | | 1
|
||||
|
@ -60,7 +72,7 @@ LL | | };
|
|||
= note: `(x + y < 4) as i32` or `(x + y < 4).into()` can also be valid options
|
||||
|
||||
error: boolean to int conversion using if
|
||||
--> $DIR/bool_to_int_with_if.rs:44:12
|
||||
--> $DIR/bool_to_int_with_if.rs:49:12
|
||||
|
|
||||
LL | } else if b {
|
||||
| ____________^
|
||||
|
@ -68,17 +80,30 @@ LL | | 1
|
|||
LL | | } else {
|
||||
LL | | 0
|
||||
LL | | };
|
||||
| |_____^ help: replace with from: `{i32::from(b)}`
|
||||
| |_____^ help: replace with from: `{ i32::from(b) }`
|
||||
|
|
||||
= note: `b as i32` or `b.into()` can also be valid options
|
||||
|
||||
error: boolean to int conversion using if
|
||||
--> $DIR/bool_to_int_with_if.rs:102:5
|
||||
--> $DIR/bool_to_int_with_if.rs:58:12
|
||||
|
|
||||
LL | } else if b {
|
||||
| ____________^
|
||||
LL | | 0
|
||||
LL | | } else {
|
||||
LL | | 1
|
||||
LL | | };
|
||||
| |_____^ help: replace with from: `{ i32::from(!b) }`
|
||||
|
|
||||
= note: `!b as i32` or `(!b).into()` can also be valid options
|
||||
|
||||
error: boolean to int conversion using if
|
||||
--> $DIR/bool_to_int_with_if.rs:116:5
|
||||
|
|
||||
LL | if a { 1 } else { 0 }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)`
|
||||
|
|
||||
= note: `a as u8` or `a.into()` can also be valid options
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
|
|
|
@ -139,6 +139,9 @@ fn main() {
|
|||
// Fix #5962
|
||||
if matches!(true, true) && matches!(true, true) {}
|
||||
|
||||
// Issue #9375
|
||||
if matches!(true, true) && truth() && matches!(true, true) {}
|
||||
|
||||
if true {
|
||||
#[cfg(not(teehee))]
|
||||
if true {
|
||||
|
|
|
@ -155,6 +155,11 @@ fn main() {
|
|||
if matches!(true, true) {}
|
||||
}
|
||||
|
||||
// Issue #9375
|
||||
if matches!(true, true) && truth() {
|
||||
if matches!(true, true) {}
|
||||
}
|
||||
|
||||
if true {
|
||||
#[cfg(not(teehee))]
|
||||
if true {
|
||||
|
|
|
@ -126,5 +126,13 @@ LL | | if matches!(true, true) {}
|
|||
LL | | }
|
||||
| |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: this `if` statement can be collapsed
|
||||
--> $DIR/collapsible_if.rs:159:5
|
||||
|
|
||||
LL | / if matches!(true, true) && truth() {
|
||||
LL | | if matches!(true, true) {}
|
||||
LL | | }
|
||||
| |_____^ help: collapse nested if block: `if matches!(true, true) && truth() && matches!(true, true) {}`
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
|
|
5
tests/ui/crashes/ice-9463.rs
Normal file
5
tests/ui/crashes/ice-9463.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
#![deny(arithmetic_overflow, const_err)]
|
||||
fn main() {
|
||||
let _x = -1_i32 >> -1;
|
||||
let _y = 1u32 >> 10000000000000u32;
|
||||
}
|
29
tests/ui/crashes/ice-9463.stderr
Normal file
29
tests/ui/crashes/ice-9463.stderr
Normal file
|
@ -0,0 +1,29 @@
|
|||
error: this arithmetic operation will overflow
|
||||
--> $DIR/ice-9463.rs:3:14
|
||||
|
|
||||
LL | let _x = -1_i32 >> -1;
|
||||
| ^^^^^^^^^^^^ attempt to shift right by `-1_i32`, which would overflow
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/ice-9463.rs:1:9
|
||||
|
|
||||
LL | #![deny(arithmetic_overflow, const_err)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this arithmetic operation will overflow
|
||||
--> $DIR/ice-9463.rs:4:14
|
||||
|
|
||||
LL | let _y = 1u32 >> 10000000000000u32;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift right by `1316134912_u32`, which would overflow
|
||||
|
||||
error: literal out of range for `u32`
|
||||
--> $DIR/ice-9463.rs:4:22
|
||||
|
|
||||
LL | let _y = 1u32 >> 10000000000000u32;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[deny(overflowing_literals)]` on by default
|
||||
= note: the literal `10000000000000u32` does not fit into the type `u32` whose range is `0..=4294967295`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
213
tests/ui/derivable_impls.fixed
Normal file
213
tests/ui/derivable_impls.fixed
Normal file
|
@ -0,0 +1,213 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Default)]
|
||||
struct FooDefault<'a> {
|
||||
a: bool,
|
||||
b: i32,
|
||||
c: u64,
|
||||
d: Vec<i32>,
|
||||
e: FooND1,
|
||||
f: FooND2,
|
||||
g: HashMap<i32, i32>,
|
||||
h: (i32, Vec<i32>),
|
||||
i: [Vec<i32>; 3],
|
||||
j: [i32; 5],
|
||||
k: Option<i32>,
|
||||
l: &'a [i32],
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Default)]
|
||||
struct TupleDefault(bool, i32, u64);
|
||||
|
||||
|
||||
|
||||
struct FooND1 {
|
||||
a: bool,
|
||||
}
|
||||
|
||||
impl std::default::Default for FooND1 {
|
||||
fn default() -> Self {
|
||||
Self { a: true }
|
||||
}
|
||||
}
|
||||
|
||||
struct FooND2 {
|
||||
a: i32,
|
||||
}
|
||||
|
||||
impl std::default::Default for FooND2 {
|
||||
fn default() -> Self {
|
||||
Self { a: 5 }
|
||||
}
|
||||
}
|
||||
|
||||
struct FooNDNew {
|
||||
a: bool,
|
||||
}
|
||||
|
||||
impl FooNDNew {
|
||||
fn new() -> Self {
|
||||
Self { a: true }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FooNDNew {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
struct FooNDVec(Vec<i32>);
|
||||
|
||||
impl Default for FooNDVec {
|
||||
fn default() -> Self {
|
||||
Self(vec![5, 12])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct StrDefault<'a>(&'a str);
|
||||
|
||||
|
||||
|
||||
#[derive(Default)]
|
||||
struct AlreadyDerived(i32, bool);
|
||||
|
||||
macro_rules! mac {
|
||||
() => {
|
||||
0
|
||||
};
|
||||
($e:expr) => {
|
||||
struct X(u32);
|
||||
impl Default for X {
|
||||
fn default() -> Self {
|
||||
Self($e)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mac!(0);
|
||||
|
||||
#[derive(Default)]
|
||||
struct Y(u32);
|
||||
|
||||
|
||||
struct RustIssue26925<T> {
|
||||
a: Option<T>,
|
||||
}
|
||||
|
||||
// We should watch out for cases where a manual impl is needed because a
|
||||
// derive adds different type bounds (https://github.com/rust-lang/rust/issues/26925).
|
||||
// For example, a struct with Option<T> does not require T: Default, but a derive adds
|
||||
// that type bound anyways. So until #26925 get fixed we should disable lint
|
||||
// for the following case
|
||||
impl<T> Default for RustIssue26925<T> {
|
||||
fn default() -> Self {
|
||||
Self { a: None }
|
||||
}
|
||||
}
|
||||
|
||||
struct SpecializedImpl<A, B> {
|
||||
a: A,
|
||||
b: B,
|
||||
}
|
||||
|
||||
impl<T: Default> Default for SpecializedImpl<T, T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
a: T::default(),
|
||||
b: T::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct WithoutSelfCurly {
|
||||
a: bool,
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Default)]
|
||||
struct WithoutSelfParan(bool);
|
||||
|
||||
|
||||
|
||||
// https://github.com/rust-lang/rust-clippy/issues/7655
|
||||
|
||||
pub struct SpecializedImpl2<T> {
|
||||
v: Vec<T>,
|
||||
}
|
||||
|
||||
impl Default for SpecializedImpl2<String> {
|
||||
fn default() -> Self {
|
||||
Self { v: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/rust-lang/rust-clippy/issues/7654
|
||||
|
||||
pub struct Color {
|
||||
pub r: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
}
|
||||
|
||||
/// `#000000`
|
||||
impl Default for Color {
|
||||
fn default() -> Self {
|
||||
Color { r: 0, g: 0, b: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Color2 {
|
||||
pub r: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
}
|
||||
|
||||
impl Default for Color2 {
|
||||
/// `#000000`
|
||||
fn default() -> Self {
|
||||
Self { r: 0, g: 0, b: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RepeatDefault1 {
|
||||
a: [i8; 32],
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct RepeatDefault2 {
|
||||
a: [i8; 33],
|
||||
}
|
||||
|
||||
impl Default for RepeatDefault2 {
|
||||
fn default() -> Self {
|
||||
RepeatDefault2 { a: [0; 33] }
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/rust-lang/rust-clippy/issues/7753
|
||||
|
||||
pub enum IntOrString {
|
||||
Int(i32),
|
||||
String(String),
|
||||
}
|
||||
|
||||
impl Default for IntOrString {
|
||||
fn default() -> Self {
|
||||
IntOrString::Int(0)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,3 +1,7 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
struct FooDefault<'a> {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: this `impl` can be derived
|
||||
--> $DIR/derivable_impls.rs:18:1
|
||||
--> $DIR/derivable_impls.rs:22:1
|
||||
|
|
||||
LL | / impl std::default::Default for FooDefault<'_> {
|
||||
LL | | fn default() -> Self {
|
||||
|
@ -11,10 +11,14 @@ LL | | }
|
|||
| |_^
|
||||
|
|
||||
= note: `-D clippy::derivable-impls` implied by `-D warnings`
|
||||
= help: try annotating `FooDefault` with `#[derive(Default)]`
|
||||
= help: remove the manual implementation...
|
||||
help: ...and instead derive it
|
||||
|
|
||||
LL | #[derive(Default)]
|
||||
|
|
||||
|
||||
error: this `impl` can be derived
|
||||
--> $DIR/derivable_impls.rs:39:1
|
||||
--> $DIR/derivable_impls.rs:43:1
|
||||
|
|
||||
LL | / impl std::default::Default for TupleDefault {
|
||||
LL | | fn default() -> Self {
|
||||
|
@ -23,10 +27,14 @@ LL | | }
|
|||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
= help: try annotating `TupleDefault` with `#[derive(Default)]`
|
||||
= help: remove the manual implementation...
|
||||
help: ...and instead derive it
|
||||
|
|
||||
LL | #[derive(Default)]
|
||||
|
|
||||
|
||||
error: this `impl` can be derived
|
||||
--> $DIR/derivable_impls.rs:91:1
|
||||
--> $DIR/derivable_impls.rs:95:1
|
||||
|
|
||||
LL | / impl Default for StrDefault<'_> {
|
||||
LL | | fn default() -> Self {
|
||||
|
@ -35,10 +43,14 @@ LL | | }
|
|||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
= help: try annotating `StrDefault` with `#[derive(Default)]`
|
||||
= help: remove the manual implementation...
|
||||
help: ...and instead derive it
|
||||
|
|
||||
LL | #[derive(Default)]
|
||||
|
|
||||
|
||||
error: this `impl` can be derived
|
||||
--> $DIR/derivable_impls.rs:117:1
|
||||
--> $DIR/derivable_impls.rs:121:1
|
||||
|
|
||||
LL | / impl Default for Y {
|
||||
LL | | fn default() -> Self {
|
||||
|
@ -47,10 +59,14 @@ LL | | }
|
|||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
= help: try annotating `Y` with `#[derive(Default)]`
|
||||
= help: remove the manual implementation...
|
||||
help: ...and instead derive it
|
||||
|
|
||||
LL | #[derive(Default)]
|
||||
|
|
||||
|
||||
error: this `impl` can be derived
|
||||
--> $DIR/derivable_impls.rs:156:1
|
||||
--> $DIR/derivable_impls.rs:160:1
|
||||
|
|
||||
LL | / impl Default for WithoutSelfCurly {
|
||||
LL | | fn default() -> Self {
|
||||
|
@ -59,10 +75,14 @@ LL | | }
|
|||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
= help: try annotating `WithoutSelfCurly` with `#[derive(Default)]`
|
||||
= help: remove the manual implementation...
|
||||
help: ...and instead derive it
|
||||
|
|
||||
LL | #[derive(Default)]
|
||||
|
|
||||
|
||||
error: this `impl` can be derived
|
||||
--> $DIR/derivable_impls.rs:164:1
|
||||
--> $DIR/derivable_impls.rs:168:1
|
||||
|
|
||||
LL | / impl Default for WithoutSelfParan {
|
||||
LL | | fn default() -> Self {
|
||||
|
@ -71,10 +91,14 @@ LL | | }
|
|||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
= help: try annotating `WithoutSelfParan` with `#[derive(Default)]`
|
||||
= help: remove the manual implementation...
|
||||
help: ...and instead derive it
|
||||
|
|
||||
LL | #[derive(Default)]
|
||||
|
|
||||
|
||||
error: this `impl` can be derived
|
||||
--> $DIR/derivable_impls.rs:214:1
|
||||
--> $DIR/derivable_impls.rs:218:1
|
||||
|
|
||||
LL | / impl Default for RepeatDefault1 {
|
||||
LL | | fn default() -> Self {
|
||||
|
@ -83,7 +107,11 @@ LL | | }
|
|||
LL | | }
|
||||
| |_^
|
||||
|
|
||||
= help: try annotating `RepeatDefault1` with `#[derive(Default)]`
|
||||
= help: remove the manual implementation...
|
||||
help: ...and instead derive it
|
||||
|
|
||||
LL | #[derive(Default)]
|
||||
|
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
|
|
@ -45,5 +45,13 @@ fn main() {
|
|||
eprint!("\r\n");
|
||||
eprint!("foo\r\n");
|
||||
eprint!("\\r\n"); //~ ERROR
|
||||
eprint!("foo\rbar\n") // ~ ERROR
|
||||
eprint!("foo\rbar\n");
|
||||
|
||||
// Ignore expanded format strings
|
||||
macro_rules! newline {
|
||||
() => {
|
||||
"\n"
|
||||
};
|
||||
}
|
||||
eprint!(newline!());
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ LL | | );
|
|||
help: use `eprintln!` instead
|
||||
|
|
||||
LL ~ eprintln!(
|
||||
LL ~ ""
|
||||
LL ~
|
||||
|
|
||||
|
||||
error: using `eprint!()` with a format string that ends in a single newline
|
||||
|
@ -98,7 +98,7 @@ LL | | );
|
|||
help: use `eprintln!` instead
|
||||
|
|
||||
LL ~ eprintln!(
|
||||
LL ~ r""
|
||||
LL ~
|
||||
|
|
||||
|
||||
error: using `eprint!()` with a format string that ends in a single newline
|
||||
|
@ -113,17 +113,5 @@ LL - eprint!("/r/n"); //~ ERROR
|
|||
LL + eprintln!("/r"); //~ ERROR
|
||||
|
|
||||
|
||||
error: using `eprint!()` with a format string that ends in a single newline
|
||||
--> $DIR/eprint_with_newline.rs:48:5
|
||||
|
|
||||
LL | eprint!("foo/rbar/n") // ~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use `eprintln!` instead
|
||||
|
|
||||
LL - eprint!("foo/rbar/n") // ~ ERROR
|
||||
LL + eprintln!("foo/rbar") // ~ ERROR
|
||||
|
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
|
|
|
@ -36,6 +36,8 @@ fn main() {
|
|||
eprintln!("with {} {}", 2, value);
|
||||
eprintln!("with {value}");
|
||||
eprintln!("macro arg {}", one!());
|
||||
let width = 2;
|
||||
eprintln!("{:w$}", value, w = width);
|
||||
}
|
||||
// these should not warn, different destination
|
||||
{
|
||||
|
|
|
@ -36,6 +36,8 @@ fn main() {
|
|||
writeln!(std::io::stderr(), "with {} {}", 2, value).unwrap();
|
||||
writeln!(std::io::stderr(), "with {value}").unwrap();
|
||||
writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap();
|
||||
let width = 2;
|
||||
writeln!(std::io::stderr(), "{:w$}", value, w = width).unwrap();
|
||||
}
|
||||
// these should not warn, different destination
|
||||
{
|
||||
|
|
|
@ -72,5 +72,11 @@ error: use of `writeln!(stderr(), ...).unwrap()`
|
|||
LL | writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("macro arg {}", one!())`
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: use of `writeln!(stderr(), ...).unwrap()`
|
||||
--> $DIR/explicit_write.rs:40:9
|
||||
|
|
||||
LL | writeln!(std::io::stderr(), "{:w$}", value, w = width).unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("{:w$}", value, w = width)`
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
|
|
|
@ -28,8 +28,6 @@ fn main() {
|
|||
format!("{:?}", "foo"); // Don't warn about `Debug`.
|
||||
format!("{:8}", "foo");
|
||||
format!("{:width$}", "foo", width = 8);
|
||||
"foo".to_string(); // Warn when the format makes no difference.
|
||||
"foo".to_string(); // Warn when the format makes no difference.
|
||||
format!("foo {}", "bar");
|
||||
format!("{} bar", "foo");
|
||||
|
||||
|
@ -38,8 +36,6 @@ fn main() {
|
|||
format!("{:?}", arg); // Don't warn about debug.
|
||||
format!("{:8}", arg);
|
||||
format!("{:width$}", arg, width = 8);
|
||||
arg.to_string(); // Warn when the format makes no difference.
|
||||
arg.to_string(); // Warn when the format makes no difference.
|
||||
format!("foo {}", arg);
|
||||
format!("{} bar", arg);
|
||||
|
||||
|
|
|
@ -30,8 +30,6 @@ fn main() {
|
|||
format!("{:?}", "foo"); // Don't warn about `Debug`.
|
||||
format!("{:8}", "foo");
|
||||
format!("{:width$}", "foo", width = 8);
|
||||
format!("{:+}", "foo"); // Warn when the format makes no difference.
|
||||
format!("{:<}", "foo"); // Warn when the format makes no difference.
|
||||
format!("foo {}", "bar");
|
||||
format!("{} bar", "foo");
|
||||
|
||||
|
@ -40,8 +38,6 @@ fn main() {
|
|||
format!("{:?}", arg); // Don't warn about debug.
|
||||
format!("{:8}", arg);
|
||||
format!("{:width$}", arg, width = 8);
|
||||
format!("{:+}", arg); // Warn when the format makes no difference.
|
||||
format!("{:<}", arg); // Warn when the format makes no difference.
|
||||
format!("foo {}", arg);
|
||||
format!("{} bar", arg);
|
||||
|
||||
|
|
|
@ -46,82 +46,58 @@ LL | format!("{}", "foo");
|
|||
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:33:5
|
||||
|
|
||||
LL | format!("{:+}", "foo"); // Warn when the format makes no difference.
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:34:5
|
||||
|
|
||||
LL | format!("{:<}", "foo"); // Warn when the format makes no difference.
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:39:5
|
||||
--> $DIR/format.rs:37:5
|
||||
|
|
||||
LL | format!("{}", arg);
|
||||
| ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:43:5
|
||||
|
|
||||
LL | format!("{:+}", arg); // Warn when the format makes no difference.
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:44:5
|
||||
|
|
||||
LL | format!("{:<}", arg); // Warn when the format makes no difference.
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:71:5
|
||||
--> $DIR/format.rs:67:5
|
||||
|
|
||||
LL | format!("{}", 42.to_string());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:73:5
|
||||
--> $DIR/format.rs:69:5
|
||||
|
|
||||
LL | format!("{}", x.display().to_string());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:77:18
|
||||
--> $DIR/format.rs:73:18
|
||||
|
|
||||
LL | let _ = Some(format!("{}", a + "bar"));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:81:22
|
||||
--> $DIR/format.rs:77:22
|
||||
|
|
||||
LL | let _s: String = format!("{}", &*v.join("/n"));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:87:13
|
||||
--> $DIR/format.rs:83:13
|
||||
|
|
||||
LL | let _ = format!("{x}");
|
||||
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:89:13
|
||||
--> $DIR/format.rs:85:13
|
||||
|
|
||||
LL | let _ = format!("{y}", y = x);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:93:13
|
||||
--> $DIR/format.rs:89:13
|
||||
|
|
||||
LL | let _ = format!("{abc}");
|
||||
| ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:95:13
|
||||
--> $DIR/format.rs:91:13
|
||||
|
|
||||
LL | let _ = format!("{xx}");
|
||||
| ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()`
|
||||
|
||||
error: aborting due to 19 previous errors
|
||||
error: aborting due to 15 previous errors
|
||||
|
||||
|
|
64
tests/ui/iter_kv_map.fixed
Normal file
64
tests/ui/iter_kv_map.fixed
Normal file
|
@ -0,0 +1,64 @@
|
|||
// run-rustfix
|
||||
|
||||
#![warn(clippy::iter_kv_map)]
|
||||
#![allow(clippy::redundant_clone)]
|
||||
#![allow(clippy::suspicious_map)]
|
||||
#![allow(clippy::map_identity)]
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
fn main() {
|
||||
let get_key = |(key, _val)| key;
|
||||
|
||||
let map: HashMap<u32, u32> = HashMap::new();
|
||||
|
||||
let _ = map.keys().collect::<Vec<_>>();
|
||||
let _ = map.values().collect::<Vec<_>>();
|
||||
let _ = map.values().map(|v| v + 2).collect::<Vec<_>>();
|
||||
|
||||
let _ = map.clone().into_keys().collect::<Vec<_>>();
|
||||
let _ = map.clone().into_keys().map(|key| key + 2).collect::<Vec<_>>();
|
||||
|
||||
let _ = map.clone().into_values().collect::<Vec<_>>();
|
||||
let _ = map.clone().into_values().map(|val| val + 2).collect::<Vec<_>>();
|
||||
|
||||
let _ = map.clone().values().collect::<Vec<_>>();
|
||||
let _ = map.keys().filter(|x| *x % 2 == 0).count();
|
||||
|
||||
// Don't lint
|
||||
let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
|
||||
let _ = map.iter().map(get_key).collect::<Vec<_>>();
|
||||
|
||||
// Linting the following could be an improvement to the lint
|
||||
// map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
|
||||
|
||||
// Lint
|
||||
let _ = map.keys().map(|key| key * 9).count();
|
||||
let _ = map.values().map(|value| value * 17).count();
|
||||
|
||||
let map: BTreeMap<u32, u32> = BTreeMap::new();
|
||||
|
||||
let _ = map.keys().collect::<Vec<_>>();
|
||||
let _ = map.values().collect::<Vec<_>>();
|
||||
let _ = map.values().map(|v| v + 2).collect::<Vec<_>>();
|
||||
|
||||
let _ = map.clone().into_keys().collect::<Vec<_>>();
|
||||
let _ = map.clone().into_keys().map(|key| key + 2).collect::<Vec<_>>();
|
||||
|
||||
let _ = map.clone().into_values().collect::<Vec<_>>();
|
||||
let _ = map.clone().into_values().map(|val| val + 2).collect::<Vec<_>>();
|
||||
|
||||
let _ = map.clone().values().collect::<Vec<_>>();
|
||||
let _ = map.keys().filter(|x| *x % 2 == 0).count();
|
||||
|
||||
// Don't lint
|
||||
let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
|
||||
let _ = map.iter().map(get_key).collect::<Vec<_>>();
|
||||
|
||||
// Linting the following could be an improvement to the lint
|
||||
// map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
|
||||
|
||||
// Lint
|
||||
let _ = map.keys().map(|key| key * 9).count();
|
||||
let _ = map.values().map(|value| value * 17).count();
|
||||
}
|
64
tests/ui/iter_kv_map.rs
Normal file
64
tests/ui/iter_kv_map.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
// run-rustfix
|
||||
|
||||
#![warn(clippy::iter_kv_map)]
|
||||
#![allow(clippy::redundant_clone)]
|
||||
#![allow(clippy::suspicious_map)]
|
||||
#![allow(clippy::map_identity)]
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
fn main() {
|
||||
let get_key = |(key, _val)| key;
|
||||
|
||||
let map: HashMap<u32, u32> = HashMap::new();
|
||||
|
||||
let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
|
||||
let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
|
||||
let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
|
||||
|
||||
let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
|
||||
let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
|
||||
|
||||
let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
|
||||
let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
|
||||
|
||||
let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
|
||||
let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
|
||||
|
||||
// Don't lint
|
||||
let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
|
||||
let _ = map.iter().map(get_key).collect::<Vec<_>>();
|
||||
|
||||
// Linting the following could be an improvement to the lint
|
||||
// map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
|
||||
|
||||
// Lint
|
||||
let _ = map.iter().map(|(key, _value)| key * 9).count();
|
||||
let _ = map.iter().map(|(_key, value)| value * 17).count();
|
||||
|
||||
let map: BTreeMap<u32, u32> = BTreeMap::new();
|
||||
|
||||
let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
|
||||
let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
|
||||
let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
|
||||
|
||||
let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
|
||||
let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
|
||||
|
||||
let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
|
||||
let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
|
||||
|
||||
let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
|
||||
let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
|
||||
|
||||
// Don't lint
|
||||
let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count();
|
||||
let _ = map.iter().map(get_key).collect::<Vec<_>>();
|
||||
|
||||
// Linting the following could be an improvement to the lint
|
||||
// map.iter().filter_map(|(_, val)| (val % 2 == 0).then(val * 17)).count();
|
||||
|
||||
// Lint
|
||||
let _ = map.iter().map(|(key, _value)| key * 9).count();
|
||||
let _ = map.iter().map(|(_key, value)| value * 17).count();
|
||||
}
|
136
tests/ui/iter_kv_map.stderr
Normal file
136
tests/ui/iter_kv_map.stderr
Normal file
|
@ -0,0 +1,136 @@
|
|||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:15:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
|
||||
|
|
||||
= note: `-D clippy::iter-kv-map` implied by `-D warnings`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:16:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:17:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:19:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:20:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:22:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:23:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:25:13
|
||||
|
|
||||
LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:26:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:36:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(key, _value)| key * 9).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:37:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(_key, value)| value * 17).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:41:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(key, _)| key).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:42:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:43:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:45:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:46:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:48:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:49:13
|
||||
|
|
||||
LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:51:13
|
||||
|
|
||||
LL | let _ = map.clone().iter().map(|(_, val)| val).collect::<Vec<_>>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:52:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()`
|
||||
|
||||
error: iterating on a map's keys
|
||||
--> $DIR/iter_kv_map.rs:62:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(key, _value)| key * 9).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> $DIR/iter_kv_map.rs:63:13
|
||||
|
|
||||
LL | let _ = map.iter().map(|(_key, value)| value * 17).count();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)`
|
||||
|
||||
error: aborting due to 22 previous errors
|
||||
|
|
@ -101,12 +101,12 @@ struct Struct2 {
|
|||
#[derive(Copy, Clone)]
|
||||
enum CopyableLargeEnum {
|
||||
A(bool),
|
||||
B([u128; 4000]),
|
||||
B([u64; 8000]),
|
||||
}
|
||||
|
||||
enum ManuallyCopyLargeEnum {
|
||||
A(bool),
|
||||
B([u128; 4000]),
|
||||
B([u64; 8000]),
|
||||
}
|
||||
|
||||
impl Clone for ManuallyCopyLargeEnum {
|
||||
|
|
|
@ -167,8 +167,8 @@ error: large size difference between variants
|
|||
LL | / enum CopyableLargeEnum {
|
||||
LL | | A(bool),
|
||||
| | ------- the second-largest variant contains at least 1 bytes
|
||||
LL | | B([u128; 4000]),
|
||||
| | --------------- the largest variant contains at least 64000 bytes
|
||||
LL | | B([u64; 8000]),
|
||||
| | -------------- the largest variant contains at least 64000 bytes
|
||||
LL | | }
|
||||
| |_^ the entire enum is at least 64008 bytes
|
||||
|
|
||||
|
@ -180,8 +180,8 @@ LL | enum CopyableLargeEnum {
|
|||
help: consider boxing the large fields to reduce the total size of the enum
|
||||
--> $DIR/large_enum_variant.rs:104:5
|
||||
|
|
||||
LL | B([u128; 4000]),
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | B([u64; 8000]),
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: large size difference between variants
|
||||
--> $DIR/large_enum_variant.rs:107:1
|
||||
|
@ -189,8 +189,8 @@ error: large size difference between variants
|
|||
LL | / enum ManuallyCopyLargeEnum {
|
||||
LL | | A(bool),
|
||||
| | ------- the second-largest variant contains at least 1 bytes
|
||||
LL | | B([u128; 4000]),
|
||||
| | --------------- the largest variant contains at least 64000 bytes
|
||||
LL | | B([u64; 8000]),
|
||||
| | -------------- the largest variant contains at least 64000 bytes
|
||||
LL | | }
|
||||
| |_^ the entire enum is at least 64008 bytes
|
||||
|
|
||||
|
@ -202,8 +202,8 @@ LL | enum ManuallyCopyLargeEnum {
|
|||
help: consider boxing the large fields to reduce the total size of the enum
|
||||
--> $DIR/large_enum_variant.rs:109:5
|
||||
|
|
||||
LL | B([u128; 4000]),
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | B([u64; 8000]),
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: large size difference between variants
|
||||
--> $DIR/large_enum_variant.rs:120:1
|
||||
|
|
|
@ -12,6 +12,12 @@ enum E {
|
|||
T(u32),
|
||||
}
|
||||
|
||||
pub static DOESNOTLINT: [u8; 512_001] = [0; 512_001];
|
||||
pub static DOESNOTLINT2: [u8; 512_001] = {
|
||||
let x = 0;
|
||||
[x; 512_001]
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let bad = (
|
||||
[0u32; 20_000_000],
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: allocating a local array larger than 512000 bytes
|
||||
--> $DIR/large_stack_arrays.rs:17:9
|
||||
--> $DIR/large_stack_arrays.rs:23:9
|
||||
|
|
||||
LL | [0u32; 20_000_000],
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
@ -8,7 +8,7 @@ LL | [0u32; 20_000_000],
|
|||
= help: consider allocating on the heap with `vec![0u32; 20_000_000].into_boxed_slice()`
|
||||
|
||||
error: allocating a local array larger than 512000 bytes
|
||||
--> $DIR/large_stack_arrays.rs:18:9
|
||||
--> $DIR/large_stack_arrays.rs:24:9
|
||||
|
|
||||
LL | [S { data: [0; 32] }; 5000],
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -16,7 +16,7 @@ LL | [S { data: [0; 32] }; 5000],
|
|||
= help: consider allocating on the heap with `vec![S { data: [0; 32] }; 5000].into_boxed_slice()`
|
||||
|
||||
error: allocating a local array larger than 512000 bytes
|
||||
--> $DIR/large_stack_arrays.rs:19:9
|
||||
--> $DIR/large_stack_arrays.rs:25:9
|
||||
|
|
||||
LL | [Some(""); 20_000_000],
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -24,7 +24,7 @@ LL | [Some(""); 20_000_000],
|
|||
= help: consider allocating on the heap with `vec![Some(""); 20_000_000].into_boxed_slice()`
|
||||
|
||||
error: allocating a local array larger than 512000 bytes
|
||||
--> $DIR/large_stack_arrays.rs:20:9
|
||||
--> $DIR/large_stack_arrays.rs:26:9
|
||||
|
|
||||
LL | [E::T(0); 5000],
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -274,7 +274,7 @@ impl AsyncLen {
|
|||
}
|
||||
|
||||
pub async fn len(&self) -> usize {
|
||||
if self.async_task().await { 0 } else { 1 }
|
||||
usize::from(!self.async_task().await)
|
||||
}
|
||||
|
||||
pub async fn is_empty(&self) -> bool {
|
||||
|
|
|
@ -57,3 +57,9 @@ fn check_expect() {
|
|||
#[expect(clippy::nonminimal_bool)]
|
||||
let _ = !!a;
|
||||
}
|
||||
|
||||
fn issue9428() {
|
||||
if matches!(true, true) && true {
|
||||
println!("foo");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,5 +107,11 @@ LL | let _ = !(a == b || c == d);
|
|||
LL | let _ = a != b && c != d;
|
||||
| ~~~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: this boolean expression can be simplified
|
||||
--> $DIR/nonminimal_bool.rs:62:8
|
||||
|
|
||||
LL | if matches!(true, true) && true {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(true, true)`
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
// run-rustfix
|
||||
#![allow(unused_must_use)]
|
||||
#![allow(named_arguments_used_positionally)] // Unstable at time of writing.
|
||||
#![warn(clippy::positional_named_format_parameters)]
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
fn main() {
|
||||
let mut v = Vec::new();
|
||||
let hello = "Hello";
|
||||
|
||||
println!("{hello:.foo$}", foo = 2);
|
||||
writeln!(v, "{hello:.foo$}", foo = 2);
|
||||
|
||||
// Warnings
|
||||
println!("{zero} {one:?}", zero = 0, one = 1);
|
||||
println!("This is a test {zero} {one:?}", zero = 0, one = 1);
|
||||
println!("Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01);
|
||||
println!("Hello {one:zero$}!", zero = 5, one = 1);
|
||||
println!("Hello {zero:one$}!", zero = 4, one = 1);
|
||||
println!("Hello {zero:0one$}!", zero = 4, one = 1);
|
||||
println!("Hello is {one:.zero$}", zero = 5, one = 0.01);
|
||||
println!("Hello is {one:<6.zero$}", zero = 5, one = 0.01);
|
||||
println!("{zero}, `{two:>8.one$}` has 3", zero = hello, one = 3, two = hello);
|
||||
println!("Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01);
|
||||
println!("Hello {world} {world}!", world = 5);
|
||||
|
||||
writeln!(v, "{zero} {one:?}", zero = 0, one = 1);
|
||||
writeln!(v, "This is a test {zero} {one:?}", zero = 0, one = 1);
|
||||
writeln!(v, "Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01);
|
||||
writeln!(v, "Hello {one:zero$}!", zero = 4, one = 1);
|
||||
writeln!(v, "Hello {zero:one$}!", zero = 4, one = 1);
|
||||
writeln!(v, "Hello {zero:0one$}!", zero = 4, one = 1);
|
||||
writeln!(v, "Hello is {one:.zero$}", zero = 3, one = 0.01);
|
||||
writeln!(v, "Hello is {one:<6.zero$}", zero = 2, one = 0.01);
|
||||
writeln!(v, "{zero}, `{two:>8.one$}` has 3", zero = hello, one = 3, two = hello);
|
||||
writeln!(v, "Hello {one} is {two:.zero$}", zero = 1, one = hello, two = 0.01);
|
||||
writeln!(v, "Hello {world} {world}!", world = 0);
|
||||
|
||||
// Tests from other files
|
||||
println!("{w:w$}", w = 1);
|
||||
println!("{p:.p$}", p = 1);
|
||||
println!("{v}", v = 1);
|
||||
println!("{v:v$}", v = 1);
|
||||
println!("{v:v$}", v = 1);
|
||||
println!("{v:v$.v$}", v = 1);
|
||||
println!("{v:v$.v$}", v = 1);
|
||||
println!("{v:v$.v$}", v = 1);
|
||||
println!("{v:v$.v$}", v = 1);
|
||||
println!("{v:v$.v$}", v = 1);
|
||||
println!("{v:v$.v$}", v = 1);
|
||||
println!("{v:v$.v$}", v = 1);
|
||||
println!("{w:w$}", w = 1);
|
||||
println!("{p:.p$}", p = 1);
|
||||
println!("{:p$.w$}", 1, w = 1, p = 1);
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
// run-rustfix
|
||||
#![allow(unused_must_use)]
|
||||
#![allow(named_arguments_used_positionally)] // Unstable at time of writing.
|
||||
#![warn(clippy::positional_named_format_parameters)]
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
fn main() {
|
||||
let mut v = Vec::new();
|
||||
let hello = "Hello";
|
||||
|
||||
println!("{hello:.foo$}", foo = 2);
|
||||
writeln!(v, "{hello:.foo$}", foo = 2);
|
||||
|
||||
// Warnings
|
||||
println!("{} {1:?}", zero = 0, one = 1);
|
||||
println!("This is a test { } {000001:?}", zero = 0, one = 1);
|
||||
println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
|
||||
println!("Hello {1:0$}!", zero = 5, one = 1);
|
||||
println!("Hello {0:1$}!", zero = 4, one = 1);
|
||||
println!("Hello {0:01$}!", zero = 4, one = 1);
|
||||
println!("Hello is {1:.*}", zero = 5, one = 0.01);
|
||||
println!("Hello is {:<6.*}", zero = 5, one = 0.01);
|
||||
println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
|
||||
println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
|
||||
println!("Hello {world} {}!", world = 5);
|
||||
|
||||
writeln!(v, "{} {1:?}", zero = 0, one = 1);
|
||||
writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1);
|
||||
writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
|
||||
writeln!(v, "Hello {1:0$}!", zero = 4, one = 1);
|
||||
writeln!(v, "Hello {0:1$}!", zero = 4, one = 1);
|
||||
writeln!(v, "Hello {0:01$}!", zero = 4, one = 1);
|
||||
writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01);
|
||||
writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01);
|
||||
writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
|
||||
writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
|
||||
writeln!(v, "Hello {world} {}!", world = 0);
|
||||
|
||||
// Tests from other files
|
||||
println!("{:w$}", w = 1);
|
||||
println!("{:.p$}", p = 1);
|
||||
println!("{}", v = 1);
|
||||
println!("{:0$}", v = 1);
|
||||
println!("{0:0$}", v = 1);
|
||||
println!("{:0$.0$}", v = 1);
|
||||
println!("{0:0$.0$}", v = 1);
|
||||
println!("{0:0$.v$}", v = 1);
|
||||
println!("{0:v$.0$}", v = 1);
|
||||
println!("{v:0$.0$}", v = 1);
|
||||
println!("{v:v$.0$}", v = 1);
|
||||
println!("{v:0$.v$}", v = 1);
|
||||
println!("{:w$}", w = 1);
|
||||
println!("{:.p$}", p = 1);
|
||||
println!("{:p$.w$}", 1, w = 1, p = 1);
|
||||
}
|
|
@ -1,418 +0,0 @@
|
|||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:16:16
|
||||
|
|
||||
LL | println!("{} {1:?}", zero = 0, one = 1);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
|
||||
= note: `-D clippy::positional-named-format-parameters` implied by `-D warnings`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:16:19
|
||||
|
|
||||
LL | println!("{} {1:?}", zero = 0, one = 1);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:17:31
|
||||
|
|
||||
LL | println!("This is a test { } {000001:?}", zero = 0, one = 1);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:17:35
|
||||
|
|
||||
LL | println!("This is a test { } {000001:?}", zero = 0, one = 1);
|
||||
| ^^^^^^ help: replace it with: `one`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:18:32
|
||||
|
|
||||
LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:18:22
|
||||
|
|
||||
LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter two is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:18:29
|
||||
|
|
||||
LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
|
||||
| ^ help: replace it with: `two`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:19:24
|
||||
|
|
||||
LL | println!("Hello {1:0$}!", zero = 5, one = 1);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:19:22
|
||||
|
|
||||
LL | println!("Hello {1:0$}!", zero = 5, one = 1);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:20:22
|
||||
|
|
||||
LL | println!("Hello {0:1$}!", zero = 4, one = 1);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:20:24
|
||||
|
|
||||
LL | println!("Hello {0:1$}!", zero = 4, one = 1);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:21:22
|
||||
|
|
||||
LL | println!("Hello {0:01$}!", zero = 4, one = 1);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:21:25
|
||||
|
|
||||
LL | println!("Hello {0:01$}!", zero = 4, one = 1);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:22:28
|
||||
|
|
||||
LL | println!("Hello is {1:.*}", zero = 5, one = 0.01);
|
||||
| ^ help: replace it with: `zero$`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:22:25
|
||||
|
|
||||
LL | println!("Hello is {1:.*}", zero = 5, one = 0.01);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:23:29
|
||||
|
|
||||
LL | println!("Hello is {:<6.*}", zero = 5, one = 0.01);
|
||||
| ^ help: replace it with: `zero$`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:23:25
|
||||
|
|
||||
LL | println!("Hello is {:<6.*}", zero = 5, one = 0.01);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:24:16
|
||||
|
|
||||
LL | println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:24:28
|
||||
|
|
||||
LL | println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
|
||||
| ^ help: replace it with: `one$`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:25:32
|
||||
|
|
||||
LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:25:22
|
||||
|
|
||||
LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter two is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:25:29
|
||||
|
|
||||
LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
|
||||
| ^ help: replace it with: `two`
|
||||
|
||||
error: named parameter world is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:26:30
|
||||
|
|
||||
LL | println!("Hello {world} {}!", world = 5);
|
||||
| ^ help: replace it with: `world`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:28:19
|
||||
|
|
||||
LL | writeln!(v, "{} {1:?}", zero = 0, one = 1);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:28:22
|
||||
|
|
||||
LL | writeln!(v, "{} {1:?}", zero = 0, one = 1);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:29:34
|
||||
|
|
||||
LL | writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:29:38
|
||||
|
|
||||
LL | writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1);
|
||||
| ^^^^^^ help: replace it with: `one`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:30:35
|
||||
|
|
||||
LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:30:25
|
||||
|
|
||||
LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter two is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:30:32
|
||||
|
|
||||
LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
|
||||
| ^ help: replace it with: `two`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:31:27
|
||||
|
|
||||
LL | writeln!(v, "Hello {1:0$}!", zero = 4, one = 1);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:31:25
|
||||
|
|
||||
LL | writeln!(v, "Hello {1:0$}!", zero = 4, one = 1);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:32:25
|
||||
|
|
||||
LL | writeln!(v, "Hello {0:1$}!", zero = 4, one = 1);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:32:27
|
||||
|
|
||||
LL | writeln!(v, "Hello {0:1$}!", zero = 4, one = 1);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:33:25
|
||||
|
|
||||
LL | writeln!(v, "Hello {0:01$}!", zero = 4, one = 1);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:33:28
|
||||
|
|
||||
LL | writeln!(v, "Hello {0:01$}!", zero = 4, one = 1);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:34:31
|
||||
|
|
||||
LL | writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01);
|
||||
| ^ help: replace it with: `zero$`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:34:28
|
||||
|
|
||||
LL | writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:35:32
|
||||
|
|
||||
LL | writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01);
|
||||
| ^ help: replace it with: `zero$`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:35:28
|
||||
|
|
||||
LL | writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:36:19
|
||||
|
|
||||
LL | writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:36:31
|
||||
|
|
||||
LL | writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
|
||||
| ^ help: replace it with: `one$`
|
||||
|
||||
error: named parameter zero is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:37:35
|
||||
|
|
||||
LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
|
||||
| ^ help: replace it with: `zero`
|
||||
|
||||
error: named parameter one is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:37:25
|
||||
|
|
||||
LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
|
||||
| ^ help: replace it with: `one`
|
||||
|
||||
error: named parameter two is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:37:32
|
||||
|
|
||||
LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
|
||||
| ^ help: replace it with: `two`
|
||||
|
||||
error: named parameter world is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:38:33
|
||||
|
|
||||
LL | writeln!(v, "Hello {world} {}!", world = 0);
|
||||
| ^ help: replace it with: `world`
|
||||
|
||||
error: named parameter w is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:41:16
|
||||
|
|
||||
LL | println!("{:w$}", w = 1);
|
||||
| ^ help: replace it with: `w`
|
||||
|
||||
error: named parameter p is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:42:16
|
||||
|
|
||||
LL | println!("{:.p$}", p = 1);
|
||||
| ^ help: replace it with: `p`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:43:16
|
||||
|
|
||||
LL | println!("{}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:44:16
|
||||
|
|
||||
LL | println!("{:0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:44:17
|
||||
|
|
||||
LL | println!("{:0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:45:16
|
||||
|
|
||||
LL | println!("{0:0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:45:18
|
||||
|
|
||||
LL | println!("{0:0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:46:16
|
||||
|
|
||||
LL | println!("{:0$.0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:46:20
|
||||
|
|
||||
LL | println!("{:0$.0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:46:17
|
||||
|
|
||||
LL | println!("{:0$.0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:47:16
|
||||
|
|
||||
LL | println!("{0:0$.0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:47:21
|
||||
|
|
||||
LL | println!("{0:0$.0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:47:18
|
||||
|
|
||||
LL | println!("{0:0$.0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:48:16
|
||||
|
|
||||
LL | println!("{0:0$.v$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:48:18
|
||||
|
|
||||
LL | println!("{0:0$.v$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:49:16
|
||||
|
|
||||
LL | println!("{0:v$.0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:49:21
|
||||
|
|
||||
LL | println!("{0:v$.0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:50:21
|
||||
|
|
||||
LL | println!("{v:0$.0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:50:18
|
||||
|
|
||||
LL | println!("{v:0$.0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:51:21
|
||||
|
|
||||
LL | println!("{v:v$.0$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter v is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:52:18
|
||||
|
|
||||
LL | println!("{v:0$.v$}", v = 1);
|
||||
| ^ help: replace it with: `v`
|
||||
|
||||
error: named parameter w is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:53:16
|
||||
|
|
||||
LL | println!("{:w$}", w = 1);
|
||||
| ^ help: replace it with: `w`
|
||||
|
||||
error: named parameter p is used as a positional parameter
|
||||
--> $DIR/positional_named_format_parameters.rs:54:16
|
||||
|
|
||||
LL | println!("{:.p$}", p = 1);
|
||||
| ^ help: replace it with: `p`
|
||||
|
||||
error: aborting due to 69 previous errors
|
||||
|
|
@ -20,11 +20,13 @@ fn main() {
|
|||
println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
|
||||
println!("10 / 4 is {}", 2.5);
|
||||
println!("2 + 1 = {}", 3);
|
||||
println!("From expansion {}", stringify!(not a string literal));
|
||||
|
||||
// these should throw warnings
|
||||
print!("Hello {}", "world");
|
||||
println!("Hello {} {}", world, "world");
|
||||
println!("Hello {}", "world");
|
||||
println!("{} {:.4}", "a literal", 5);
|
||||
|
||||
// positional args don't change the fact
|
||||
// that we're using a literal -- this should
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:25:24
|
||||
--> $DIR/print_literal.rs:26:24
|
||||
|
|
||||
LL | print!("Hello {}", "world");
|
||||
| ^^^^^^^
|
||||
|
@ -12,7 +12,7 @@ LL + print!("Hello world");
|
|||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:26:36
|
||||
--> $DIR/print_literal.rs:27:36
|
||||
|
|
||||
LL | println!("Hello {} {}", world, "world");
|
||||
| ^^^^^^^
|
||||
|
@ -24,7 +24,7 @@ LL + println!("Hello {} world", world);
|
|||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:27:26
|
||||
--> $DIR/print_literal.rs:28:26
|
||||
|
|
||||
LL | println!("Hello {}", "world");
|
||||
| ^^^^^^^
|
||||
|
@ -36,7 +36,19 @@ LL + println!("Hello world");
|
|||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:32:25
|
||||
--> $DIR/print_literal.rs:29:26
|
||||
|
|
||||
LL | println!("{} {:.4}", "a literal", 5);
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - println!("{} {:.4}", "a literal", 5);
|
||||
LL + println!("a literal {:.4}", 5);
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:34:25
|
||||
|
|
||||
LL | println!("{0} {1}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
|
@ -48,7 +60,7 @@ LL + println!("hello {1}", "world");
|
|||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:32:34
|
||||
--> $DIR/print_literal.rs:34:34
|
||||
|
|
||||
LL | println!("{0} {1}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
|
@ -60,19 +72,7 @@ LL + println!("{0} world", "hello");
|
|||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:33:25
|
||||
|
|
||||
LL | println!("{1} {0}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - println!("{1} {0}", "hello", "world");
|
||||
LL + println!("{1} hello", "world");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:33:34
|
||||
--> $DIR/print_literal.rs:35:34
|
||||
|
|
||||
LL | println!("{1} {0}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
|
@ -84,10 +84,22 @@ LL + println!("world {0}", "hello");
|
|||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:36:29
|
||||
--> $DIR/print_literal.rs:35:25
|
||||
|
|
||||
LL | println!("{1} {0}", "hello", "world");
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - println!("{1} {0}", "hello", "world");
|
||||
LL + println!("{1} hello", "world");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:38:35
|
||||
|
|
||||
LL | println!("{foo} {bar}", foo = "hello", bar = "world");
|
||||
| ^^^^^^^^^^^^^
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
|
@ -96,10 +108,10 @@ LL + println!("hello {bar}", bar = "world");
|
|||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:36:44
|
||||
--> $DIR/print_literal.rs:38:50
|
||||
|
|
||||
LL | println!("{foo} {bar}", foo = "hello", bar = "world");
|
||||
| ^^^^^^^^^^^^^
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
|
@ -108,22 +120,10 @@ LL + println!("{foo} world", foo = "hello");
|
|||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:37:29
|
||||
--> $DIR/print_literal.rs:39:50
|
||||
|
|
||||
LL | println!("{bar} {foo}", foo = "hello", bar = "world");
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - println!("{bar} {foo}", foo = "hello", bar = "world");
|
||||
LL + println!("{bar} hello", bar = "world");
|
||||
|
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:37:44
|
||||
|
|
||||
LL | println!("{bar} {foo}", foo = "hello", bar = "world");
|
||||
| ^^^^^^^^^^^^^
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
|
@ -131,5 +131,17 @@ LL - println!("{bar} {foo}", foo = "hello", bar = "world");
|
|||
LL + println!("world {foo}", foo = "hello");
|
||||
|
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:39:35
|
||||
|
|
||||
LL | println!("{bar} {foo}", foo = "hello", bar = "world");
|
||||
| ^^^^^^^
|
||||
|
|
||||
help: try this
|
||||
|
|
||||
LL - println!("{bar} {foo}", foo = "hello", bar = "world");
|
||||
LL + println!("{bar} hello", bar = "world");
|
||||
|
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
|
|
@ -48,5 +48,13 @@ fn main() {
|
|||
print!("\r\n");
|
||||
print!("foo\r\n");
|
||||
print!("\\r\n"); //~ ERROR
|
||||
print!("foo\rbar\n") // ~ ERROR
|
||||
print!("foo\rbar\n");
|
||||
|
||||
// Ignore expanded format strings
|
||||
macro_rules! newline {
|
||||
() => {
|
||||
"\n"
|
||||
};
|
||||
}
|
||||
print!(newline!());
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ LL | | );
|
|||
help: use `println!` instead
|
||||
|
|
||||
LL ~ println!(
|
||||
LL ~ ""
|
||||
LL ~
|
||||
|
|
||||
|
||||
error: using `print!()` with a format string that ends in a single newline
|
||||
|
@ -98,7 +98,7 @@ LL | | );
|
|||
help: use `println!` instead
|
||||
|
|
||||
LL ~ println!(
|
||||
LL ~ r""
|
||||
LL ~
|
||||
|
|
||||
|
||||
error: using `print!()` with a format string that ends in a single newline
|
||||
|
@ -113,17 +113,5 @@ LL - print!("/r/n"); //~ ERROR
|
|||
LL + println!("/r"); //~ ERROR
|
||||
|
|
||||
|
||||
error: using `print!()` with a format string that ends in a single newline
|
||||
--> $DIR/print_with_newline.rs:51:5
|
||||
|
|
||||
LL | print!("foo/rbar/n") // ~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use `println!` instead
|
||||
|
|
||||
LL - print!("foo/rbar/n") // ~ ERROR
|
||||
LL + println!("foo/rbar") // ~ ERROR
|
||||
|
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
|
|
|
@ -1,28 +1,36 @@
|
|||
error: using `println!("")`
|
||||
error: empty string literal in `println!`
|
||||
--> $DIR/println_empty_string.rs:6:5
|
||||
|
|
||||
LL | println!("");
|
||||
| ^^^^^^^^^^^^ help: replace it with: `println!()`
|
||||
| ^^^^^^^^^--^
|
||||
| |
|
||||
| help: remove the empty string
|
||||
|
|
||||
= note: `-D clippy::println-empty-string` implied by `-D warnings`
|
||||
|
||||
error: using `println!("")`
|
||||
error: empty string literal in `println!`
|
||||
--> $DIR/println_empty_string.rs:9:14
|
||||
|
|
||||
LL | _ => println!(""),
|
||||
| ^^^^^^^^^^^^ help: replace it with: `println!()`
|
||||
| ^^^^^^^^^--^
|
||||
| |
|
||||
| help: remove the empty string
|
||||
|
||||
error: using `eprintln!("")`
|
||||
error: empty string literal in `eprintln!`
|
||||
--> $DIR/println_empty_string.rs:13:5
|
||||
|
|
||||
LL | eprintln!("");
|
||||
| ^^^^^^^^^^^^^ help: replace it with: `eprintln!()`
|
||||
| ^^^^^^^^^^--^
|
||||
| |
|
||||
| help: remove the empty string
|
||||
|
||||
error: using `eprintln!("")`
|
||||
error: empty string literal in `eprintln!`
|
||||
--> $DIR/println_empty_string.rs:16:14
|
||||
|
|
||||
LL | _ => eprintln!(""),
|
||||
| ^^^^^^^^^^^^^ help: replace it with: `eprintln!()`
|
||||
| ^^^^^^^^^^--^
|
||||
| |
|
||||
| help: remove the empty string
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#![allow(invalid_value)]
|
||||
#![allow(enum_intrinsics_non_enums)]
|
||||
#![allow(non_fmt_panics)]
|
||||
#![allow(named_arguments_used_positionally)]
|
||||
#![allow(temporary_cstring_as_ptr)]
|
||||
#![allow(unknown_lints)]
|
||||
#![allow(unused_labels)]
|
||||
|
@ -69,6 +70,7 @@
|
|||
#![warn(invalid_value)]
|
||||
#![warn(enum_intrinsics_non_enums)]
|
||||
#![warn(non_fmt_panics)]
|
||||
#![warn(named_arguments_used_positionally)]
|
||||
#![warn(temporary_cstring_as_ptr)]
|
||||
#![warn(unknown_lints)]
|
||||
#![warn(unused_labels)]
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#![allow(invalid_value)]
|
||||
#![allow(enum_intrinsics_non_enums)]
|
||||
#![allow(non_fmt_panics)]
|
||||
#![allow(named_arguments_used_positionally)]
|
||||
#![allow(temporary_cstring_as_ptr)]
|
||||
#![allow(unknown_lints)]
|
||||
#![allow(unused_labels)]
|
||||
|
@ -69,6 +70,7 @@
|
|||
#![warn(clippy::invalid_ref)]
|
||||
#![warn(clippy::mem_discriminant_non_enum)]
|
||||
#![warn(clippy::panic_params)]
|
||||
#![warn(clippy::positional_named_format_parameters)]
|
||||
#![warn(clippy::temporary_cstring_as_ptr)]
|
||||
#![warn(clippy::unknown_clippy_lints)]
|
||||
#![warn(clippy::unused_label)]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
|
||||
--> $DIR/rename.rs:38:9
|
||||
--> $DIR/rename.rs:39:9
|
||||
|
|
||||
LL | #![warn(clippy::blacklisted_name)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
|
||||
|
@ -7,220 +7,226 @@ LL | #![warn(clippy::blacklisted_name)]
|
|||
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
|
||||
|
||||
error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
|
||||
--> $DIR/rename.rs:39:9
|
||||
--> $DIR/rename.rs:40:9
|
||||
|
|
||||
LL | #![warn(clippy::block_in_if_condition_expr)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
|
||||
|
||||
error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
|
||||
--> $DIR/rename.rs:40:9
|
||||
--> $DIR/rename.rs:41:9
|
||||
|
|
||||
LL | #![warn(clippy::block_in_if_condition_stmt)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
|
||||
|
||||
error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
|
||||
--> $DIR/rename.rs:41:9
|
||||
--> $DIR/rename.rs:42:9
|
||||
|
|
||||
LL | #![warn(clippy::box_vec)]
|
||||
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
|
||||
|
||||
error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
|
||||
--> $DIR/rename.rs:42:9
|
||||
--> $DIR/rename.rs:43:9
|
||||
|
|
||||
LL | #![warn(clippy::const_static_lifetime)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
|
||||
|
||||
error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
|
||||
--> $DIR/rename.rs:43:9
|
||||
--> $DIR/rename.rs:44:9
|
||||
|
|
||||
LL | #![warn(clippy::cyclomatic_complexity)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
|
||||
|
||||
error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
|
||||
--> $DIR/rename.rs:44:9
|
||||
--> $DIR/rename.rs:45:9
|
||||
|
|
||||
LL | #![warn(clippy::disallowed_method)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
|
||||
|
||||
error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
|
||||
--> $DIR/rename.rs:45:9
|
||||
--> $DIR/rename.rs:46:9
|
||||
|
|
||||
LL | #![warn(clippy::disallowed_type)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
|
||||
|
||||
error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
|
||||
--> $DIR/rename.rs:46:9
|
||||
--> $DIR/rename.rs:47:9
|
||||
|
|
||||
LL | #![warn(clippy::eval_order_dependence)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
|
||||
|
||||
error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
|
||||
--> $DIR/rename.rs:47:9
|
||||
--> $DIR/rename.rs:48:9
|
||||
|
|
||||
LL | #![warn(clippy::for_loop_over_option)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
|
||||
|
||||
error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
|
||||
--> $DIR/rename.rs:48:9
|
||||
--> $DIR/rename.rs:49:9
|
||||
|
|
||||
LL | #![warn(clippy::for_loop_over_result)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
|
||||
|
||||
error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
|
||||
--> $DIR/rename.rs:49:9
|
||||
--> $DIR/rename.rs:50:9
|
||||
|
|
||||
LL | #![warn(clippy::identity_conversion)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
|
||||
|
||||
error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
|
||||
--> $DIR/rename.rs:50:9
|
||||
--> $DIR/rename.rs:51:9
|
||||
|
|
||||
LL | #![warn(clippy::if_let_some_result)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
|
||||
|
||||
error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
|
||||
--> $DIR/rename.rs:51:9
|
||||
--> $DIR/rename.rs:52:9
|
||||
|
|
||||
LL | #![warn(clippy::logic_bug)]
|
||||
| ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
|
||||
|
||||
error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
|
||||
--> $DIR/rename.rs:52:9
|
||||
--> $DIR/rename.rs:53:9
|
||||
|
|
||||
LL | #![warn(clippy::new_without_default_derive)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
|
||||
|
||||
error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
|
||||
--> $DIR/rename.rs:53:9
|
||||
--> $DIR/rename.rs:54:9
|
||||
|
|
||||
LL | #![warn(clippy::option_and_then_some)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
|
||||
|
||||
error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
|
||||
--> $DIR/rename.rs:54:9
|
||||
--> $DIR/rename.rs:55:9
|
||||
|
|
||||
LL | #![warn(clippy::option_expect_used)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
|
||||
|
||||
error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
|
||||
--> $DIR/rename.rs:55:9
|
||||
--> $DIR/rename.rs:56:9
|
||||
|
|
||||
LL | #![warn(clippy::option_map_unwrap_or)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
|
||||
|
||||
error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
|
||||
--> $DIR/rename.rs:56:9
|
||||
--> $DIR/rename.rs:57:9
|
||||
|
|
||||
LL | #![warn(clippy::option_map_unwrap_or_else)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
|
||||
|
||||
error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
|
||||
--> $DIR/rename.rs:57:9
|
||||
--> $DIR/rename.rs:58:9
|
||||
|
|
||||
LL | #![warn(clippy::option_unwrap_used)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
|
||||
|
||||
error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
|
||||
--> $DIR/rename.rs:58:9
|
||||
--> $DIR/rename.rs:59:9
|
||||
|
|
||||
LL | #![warn(clippy::ref_in_deref)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
|
||||
|
||||
error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
|
||||
--> $DIR/rename.rs:59:9
|
||||
--> $DIR/rename.rs:60:9
|
||||
|
|
||||
LL | #![warn(clippy::result_expect_used)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
|
||||
|
||||
error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
|
||||
--> $DIR/rename.rs:60:9
|
||||
--> $DIR/rename.rs:61:9
|
||||
|
|
||||
LL | #![warn(clippy::result_map_unwrap_or_else)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
|
||||
|
||||
error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
|
||||
--> $DIR/rename.rs:61:9
|
||||
--> $DIR/rename.rs:62:9
|
||||
|
|
||||
LL | #![warn(clippy::result_unwrap_used)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
|
||||
|
||||
error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
|
||||
--> $DIR/rename.rs:62:9
|
||||
--> $DIR/rename.rs:63:9
|
||||
|
|
||||
LL | #![warn(clippy::single_char_push_str)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
|
||||
|
||||
error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
|
||||
--> $DIR/rename.rs:63:9
|
||||
--> $DIR/rename.rs:64:9
|
||||
|
|
||||
LL | #![warn(clippy::stutter)]
|
||||
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
|
||||
|
||||
error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
|
||||
--> $DIR/rename.rs:64:9
|
||||
--> $DIR/rename.rs:65:9
|
||||
|
|
||||
LL | #![warn(clippy::to_string_in_display)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
|
||||
|
||||
error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
|
||||
--> $DIR/rename.rs:65:9
|
||||
--> $DIR/rename.rs:66:9
|
||||
|
|
||||
LL | #![warn(clippy::zero_width_space)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
|
||||
|
||||
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
|
||||
--> $DIR/rename.rs:66:9
|
||||
--> $DIR/rename.rs:67:9
|
||||
|
|
||||
LL | #![warn(clippy::drop_bounds)]
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
|
||||
|
||||
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
|
||||
--> $DIR/rename.rs:67:9
|
||||
--> $DIR/rename.rs:68:9
|
||||
|
|
||||
LL | #![warn(clippy::into_iter_on_array)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
|
||||
|
||||
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
|
||||
--> $DIR/rename.rs:68:9
|
||||
--> $DIR/rename.rs:69:9
|
||||
|
|
||||
LL | #![warn(clippy::invalid_atomic_ordering)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
|
||||
|
||||
error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
|
||||
--> $DIR/rename.rs:69:9
|
||||
--> $DIR/rename.rs:70:9
|
||||
|
|
||||
LL | #![warn(clippy::invalid_ref)]
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
|
||||
|
||||
error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
|
||||
--> $DIR/rename.rs:70:9
|
||||
--> $DIR/rename.rs:71:9
|
||||
|
|
||||
LL | #![warn(clippy::mem_discriminant_non_enum)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
|
||||
|
||||
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
|
||||
--> $DIR/rename.rs:71:9
|
||||
--> $DIR/rename.rs:72:9
|
||||
|
|
||||
LL | #![warn(clippy::panic_params)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
|
||||
|
||||
error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
|
||||
--> $DIR/rename.rs:73:9
|
||||
|
|
||||
LL | #![warn(clippy::positional_named_format_parameters)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
|
||||
|
||||
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
|
||||
--> $DIR/rename.rs:72:9
|
||||
--> $DIR/rename.rs:74:9
|
||||
|
|
||||
LL | #![warn(clippy::temporary_cstring_as_ptr)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
|
||||
|
||||
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
|
||||
--> $DIR/rename.rs:73:9
|
||||
--> $DIR/rename.rs:75:9
|
||||
|
|
||||
LL | #![warn(clippy::unknown_clippy_lints)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
|
||||
|
||||
error: lint `clippy::unused_label` has been renamed to `unused_labels`
|
||||
--> $DIR/rename.rs:74:9
|
||||
--> $DIR/rename.rs:76:9
|
||||
|
|
||||
LL | #![warn(clippy::unused_label)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
|
||||
|
||||
error: aborting due to 37 previous errors
|
||||
error: aborting due to 38 previous errors
|
||||
|
||||
|
|
|
@ -417,3 +417,12 @@ mod issue_9351 {
|
|||
predicates_are_satisfied(id("abc".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
mod issue_9504 {
|
||||
#![allow(dead_code)]
|
||||
|
||||
async fn foo<S: AsRef<str>>(_: S) {}
|
||||
async fn bar() {
|
||||
foo(std::path::PathBuf::new().to_string_lossy().to_string()).await;
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue