diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 58af069f1d9..88b61f07422 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -532,6 +532,7 @@ impl EarlyLintPass for CfgAttrPass { "`cfg_attr` is deprecated for rustfmt and got replaced by tool_attributes", "use", format!("{}rustfmt::skip]", attr_style), + Applicability::MachineApplicable, ); } } diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index a61e823f959..4f02b627e51 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -10,12 +10,15 @@ use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use crate::rustc::{declare_tool_lint, lint_array}; -use if_chain::if_chain; use crate::rustc::ty; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; use crate::syntax::ast::{Name, UintTy}; -use crate::utils::{contains_name, get_pat_name, match_type, paths, single_segment_path, snippet, span_lint_and_sugg, - walk_ptrs_ty}; +use crate::utils::{ + contains_name, get_pat_name, match_type, paths, single_segment_path, snippet_with_applicability, + span_lint_and_sugg, walk_ptrs_ty, +}; +use if_chain::if_chain; /// **What it does:** Checks for naive byte counts /// @@ -89,14 +92,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ByteCount { } else { &filter_args[0] }; - span_lint_and_sugg(cx, - NAIVE_BYTECOUNT, - expr.span, - "You appear to be counting bytes the naive way", - "Consider using the bytecount crate", - format!("bytecount::count({}, {})", - snippet(cx, haystack.span, ".."), - snippet(cx, needle.span, ".."))); + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + NAIVE_BYTECOUNT, + expr.span, + "You appear to be counting bytes the naive way", + "Consider using the bytecount crate", + format!("bytecount::count({}, {})", + snippet_with_applicability(cx, haystack.span, "..", &mut applicability), + snippet_with_applicability(cx, needle.span, "..", &mut applicability)), + applicability, + ); } }; } diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index a55ca04f706..206403791a1 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -27,7 +27,7 @@ use crate::rustc::{declare_tool_lint, lint_array}; use if_chain::if_chain; use crate::syntax::ast; -use crate::utils::{in_macro, snippet_block, span_lint_and_sugg, span_lint_and_then}; +use crate::utils::{in_macro, snippet_block, snippet_block_with_applicability, span_lint_and_sugg, span_lint_and_then}; use crate::utils::sugg::Sugg; use crate::rustc_errors::Applicability; @@ -128,12 +128,16 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) { then { match else_.node { ast::ExprKind::If(..) | ast::ExprKind::IfLet(..) => { - span_lint_and_sugg(cx, - COLLAPSIBLE_IF, - block.span, - "this `else { if .. }` block can be collapsed", - "try", - snippet_block(cx, else_.span, "..").into_owned()); + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + COLLAPSIBLE_IF, + block.span, + "this `else { if .. }` block can be collapsed", + "try", + snippet_block_with_applicability(cx, else_.span, "..", &mut applicability).into_owned(), + applicability, + ); } _ => (), } diff --git a/clippy_lints/src/default_trait_access.rs b/clippy_lints/src/default_trait_access.rs index 66d94e00d0d..693b47f6fff 100644 --- a/clippy_lints/src/default_trait_access.rs +++ b/clippy_lints/src/default_trait_access.rs @@ -10,9 +10,10 @@ use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use crate::rustc::{declare_tool_lint, lint_array}; -use if_chain::if_chain; use crate::rustc::ty::TyKind; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; +use if_chain::if_chain; use crate::utils::{any_parent_is_automatically_derived, match_def_path, opt_def_id, paths, span_lint_and_sugg}; @@ -80,7 +81,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DefaultTraitAccess { expr.span, &format!("Calling {} is more clear than this expression", replacement), "try", - replacement); + replacement, + Applicability::Unspecified, // First resolve the TODO above + ); } }, QPath::TypeRelative(..) => {}, diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs index 0171ac1e784..4d8345dadc3 100644 --- a/clippy_lints/src/double_comparison.rs +++ b/clippy_lints/src/double_comparison.rs @@ -13,9 +13,10 @@ use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; use crate::syntax::source_map::Span; -use crate::utils::{snippet, span_lint_and_sugg, SpanlessEq}; +use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq}; /// **What it does:** Checks for double comparions that could be simpified to a single expression. /// @@ -70,12 +71,19 @@ impl<'a, 'tcx> Pass { } macro_rules! lint_double_comparison { ($op:tt) => {{ - let lhs_str = snippet(cx, llhs.span, ""); - let rhs_str = snippet(cx, lrhs.span, ""); + let mut applicability = Applicability::MachineApplicable; + let lhs_str = snippet_with_applicability(cx, llhs.span, "", &mut applicability); + let rhs_str = snippet_with_applicability(cx, lrhs.span, "", &mut applicability); let sugg = format!("{} {} {}", lhs_str, stringify!($op), rhs_str); - span_lint_and_sugg(cx, DOUBLE_COMPARISONS, span, - "This binary expression can be simplified", - "try", sugg); + span_lint_and_sugg( + cx, + DOUBLE_COMPARISONS, + span, + "This binary expression can be simplified", + "try", + sugg, + applicability, + ); }} } match (op, lkind, rkind) { diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs index a679a97c2e7..fe4aea572e0 100644 --- a/clippy_lints/src/duration_subsec.rs +++ b/clippy_lints/src/duration_subsec.rs @@ -11,12 +11,13 @@ use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; -use if_chain::if_chain; +use crate::rustc_errors::Applicability; use crate::syntax::source_map::Spanned; +use if_chain::if_chain; use crate::consts::{constant, Constant}; use crate::utils::paths; -use crate::utils::{match_type, snippet, span_lint_and_sugg, walk_ptrs_ty}; +use crate::utils::{match_type, snippet_with_applicability, span_lint_and_sugg, walk_ptrs_ty}; /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds /// from other `Duration` methods. @@ -60,13 +61,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DurationSubsec { ("subsec_nanos", 1_000) => "subsec_micros", _ => return, }; + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, DURATION_SUBSEC, expr.span, &format!("Calling `{}()` is more concise than this calculation", suggested_fn), "try", - format!("{}.{}()", snippet(cx, args[0].span, "_"), suggested_fn), + format!("{}.{}()", snippet_with_applicability(cx, args[0].span, "_", &mut applicability), suggested_fn), + applicability, ); } } diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs index 26ffef9ebe4..cb75d983683 100644 --- a/clippy_lints/src/else_if_without_else.rs +++ b/clippy_lints/src/else_if_without_else.rs @@ -14,7 +14,7 @@ use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_ex use crate::rustc::{declare_tool_lint, lint_array}; use crate::syntax::ast::*; -use crate::utils::span_lint_and_sugg; +use crate::utils::span_help_and_lint; /// **What it does:** Checks for usage of if expressions with an `else if` branch, /// but without a final `else` branch. @@ -66,13 +66,12 @@ impl EarlyLintPass for ElseIfWithoutElse { while let ExprKind::If(_, _, Some(ref els)) = item.node { if let ExprKind::If(_, _, None) = els.node { - span_lint_and_sugg( + span_help_and_lint( cx, ELSE_IF_WITHOUT_ELSE, els.span, "if expression with an `else if`, but without a final `else`", "add an `else` block here", - String::new() ); } diff --git a/clippy_lints/src/excessive_precision.rs b/clippy_lints/src/excessive_precision.rs index 15a8d47337a..6043dd46ae7 100644 --- a/clippy_lints/src/excessive_precision.rs +++ b/clippy_lints/src/excessive_precision.rs @@ -10,15 +10,16 @@ use crate::rustc::hir; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use crate::rustc::{declare_tool_lint, lint_array}; -use if_chain::if_chain; use crate::rustc::ty::TyKind; -use std::f32; -use std::f64; -use std::fmt; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; use crate::syntax::ast::*; use crate::syntax_pos::symbol::Symbol; use crate::utils::span_lint_and_sugg; +use if_chain::if_chain; +use std::f32; +use std::f64; +use std::fmt; /// **What it does:** Checks for float literals with a precision greater /// than that supported by the underlying type @@ -68,6 +69,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExcessivePrecision { "float has excessive precision", "consider changing the type or truncating it to", sugg, + Applicability::MachineApplicable, ); } } diff --git a/clippy_lints/src/infallible_destructuring_match.rs b/clippy_lints/src/infallible_destructuring_match.rs index 7bbbe72f91d..558d101d68e 100644 --- a/clippy_lints/src/infallible_destructuring_match.rs +++ b/clippy_lints/src/infallible_destructuring_match.rs @@ -8,10 +8,11 @@ // except according to those terms. -use super::utils::{get_arg_name, match_var, remove_blocks, snippet, span_lint_and_sugg}; +use super::utils::{get_arg_name, match_var, remove_blocks, snippet_with_applicability, span_lint_and_sugg}; use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; use if_chain::if_chain; /// **What it does:** Checks for matches being used to destructure a single-variant enum @@ -71,6 +72,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { if match_var(body, arg); then { + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, INFALLIBLE_DESTRUCTURING_MATCH, @@ -80,10 +82,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { "try this", format!( "let {}({}) = {};", - snippet(cx, variant_name.span, ".."), - snippet(cx, local.pat.span, ".."), - snippet(cx, target.span, ".."), + snippet_with_applicability(cx, variant_name.span, "..", &mut applicability), + snippet_with_applicability(cx, local.pat.span, "..", &mut applicability), + snippet_with_applicability(cx, target.span, "..", &mut applicability), ), + applicability, ); } } diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 789a569f4cd..15c21d77698 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -11,12 +11,13 @@ use crate::rustc::hir::def_id::DefId; use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::ty; +use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc_data_structures::fx::FxHashSet; +use crate::rustc_errors::Applicability; use crate::syntax::ast::{Lit, LitKind, Name}; use crate::syntax::source_map::{Span, Spanned}; -use crate::utils::{get_item_name, in_macro, snippet, span_lint, span_lint_and_sugg, walk_ptrs_ty}; +use crate::utils::{get_item_name, in_macro, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty}; /// **What it does:** Checks for getting the length of something via `.len()` /// just to compare to zero, and suggests using `.is_empty()` where applicable. @@ -223,7 +224,15 @@ fn check_cmp(cx: &LateContext<'_, '_>, span: Span, method: &Expr, lit: &Expr, op } } -fn check_len(cx: &LateContext<'_, '_>, span: Span, method_name: Name, args: &[Expr], lit: &Lit, op: &str, compare_to: u32) { +fn check_len( + cx: &LateContext<'_, '_>, + span: Span, + method_name: Name, + args: &[Expr], + lit: &Lit, + op: &str, + compare_to: u32, +) { if let Spanned { node: LitKind::Int(lit, _), .. @@ -235,13 +244,15 @@ fn check_len(cx: &LateContext<'_, '_>, span: Span, method_name: Name, args: &[Ex } if method_name == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) { + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, LEN_ZERO, span, &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }), "using `is_empty` is clearer and more explicit", - format!("{}{}.is_empty()", op, snippet(cx, args[0].span, "_")), + format!("{}{}.is_empty()", op, snippet_with_applicability(cx, args[0].span, "_", &mut applicability)), + applicability, ); } } diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index bd54c068486..1efacc4ccec 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -12,6 +12,7 @@ use crate::rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; use crate::syntax::ast::*; use crate::syntax_pos; use crate::utils::{snippet_opt, span_lint_and_sugg}; @@ -300,6 +301,7 @@ impl WarningType { "mistyped literal suffix", "did you mean to write", grouping_hint.to_string(), + Applicability::MaybeIncorrect, ), WarningType::UnreadableLiteral => span_lint_and_sugg( cx, @@ -308,6 +310,7 @@ impl WarningType { "long literal lacking separators", "consider", grouping_hint.to_owned(), + Applicability::MachineApplicable, ), WarningType::LargeDigitGroups => span_lint_and_sugg( cx, @@ -316,6 +319,7 @@ impl WarningType { "digit groups should be smaller", "consider", grouping_hint.to_owned(), + Applicability::MachineApplicable, ), WarningType::InconsistentDigitGrouping => span_lint_and_sugg( cx, @@ -324,6 +328,7 @@ impl WarningType { "digits grouped inconsistently by underscores", "consider", grouping_hint.to_owned(), + Applicability::MachineApplicable, ), WarningType::DecimalRepresentation => span_lint_and_sugg( cx, @@ -332,6 +337,7 @@ impl WarningType { "integer literal has a better hexadecimal representation", "consider", grouping_hint.to_owned(), + Applicability::MachineApplicable, ), }; } diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 0d1b960cc1f..0704246d450 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -35,10 +35,12 @@ use crate::utils::{in_macro, sugg, sext}; use crate::utils::usage::mutated_variables; use crate::consts::{constant, Constant}; -use crate::utils::{get_enclosing_block, get_parent_expr, higher, is_integer_literal, is_refutable, - last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, snippet, snippet_opt, - span_help_and_lint, span_lint, span_lint_and_sugg, span_lint_and_then, SpanlessEq}; use crate::utils::paths; +use crate::utils::{ + get_enclosing_block, get_parent_expr, higher, is_integer_literal, is_refutable, last_path_segment, + match_trait_method, match_type, match_var, multispan_sugg, snippet, snippet_opt, snippet_with_applicability, + span_help_and_lint, span_lint, span_lint_and_sugg, span_lint_and_then, SpanlessEq, +}; /// **What it does:** Checks for for-loops that manually copy items between /// slices that could be optimized by having a memcpy. @@ -501,6 +503,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { // 1) it was ugly with big bodies; // 2) it was not indented properly; // 3) it wasn’t very smart (see #675). + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, WHILE_LET_LOOP, @@ -509,9 +512,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { "try", format!( "while let {} = {} {{ .. }}", - snippet(cx, arms[0].pats[0].span, ".."), - snippet(cx, matchexpr.span, "..") + snippet_with_applicability(cx, arms[0].pats[0].span, "..", &mut applicability), + snippet_with_applicability(cx, matchexpr.span, "..", &mut applicability), ), + applicability, ); } }, @@ -549,6 +553,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { "this loop could be written as a `for` loop", "try", format!("for {} in {} {{ .. }}", loop_var, iterator), + Applicability::HasPlaceholders, ); } } @@ -1004,7 +1009,7 @@ fn detect_manual_memcpy<'a, 'tcx>( let big_sugg = manual_copies .into_iter() .map(|(dst_var, src_var)| { - let start_str = Offset::positive(snippet_opt(cx, start.span).unwrap_or_else(|| "".into())); + let start_str = Offset::positive(snippet(cx, start.span, "").to_string()); let dst_offset = print_sum(&start_str, &dst_var.offset); let dst_limit = print_limit(end, dst_var.offset, &dst_var.var_name); let src_offset = print_sum(&start_str, &src_var.offset); @@ -1027,6 +1032,7 @@ fn detect_manual_memcpy<'a, 'tcx>( "it looks like you're manually copying between slices", "try replacing the loop by", big_sugg, + Applicability::Unspecified, ); } } @@ -1302,7 +1308,8 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx } fn lint_iter_method(cx: &LateContext<'_, '_>, args: &[Expr], arg: &Expr, method_name: &str) { - let object = snippet(cx, args[0].span, "_"); + let mut applicability = Applicability::MachineApplicable; + let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); let muta = if method_name == "iter_mut" { "mut " } else { @@ -1316,6 +1323,7 @@ fn lint_iter_method(cx: &LateContext<'_, '_>, args: &[Expr], arg: &Expr, method_ iteration methods", "to write this more concisely, try", format!("&{}{}", muta, object), + applicability, ) } @@ -1345,7 +1353,8 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat, arg: &Expr, expr: &Ex _ => lint_iter_method(cx, args, arg, method_name), }; } else { - let object = snippet(cx, args[0].span, "_"); + let mut applicability = Applicability::MachineApplicable; + let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); span_lint_and_sugg( cx, EXPLICIT_INTO_ITER_LOOP, @@ -1354,6 +1363,7 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat, arg: &Expr, expr: &Ex iteration methods`", "to write this more concisely, try", object.to_string(), + applicability, ); } } else if method_name == "next" && match_trait_method(cx, arg, &paths::ITERATOR) { diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index b2c08e6ae8c..4424143160c 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -11,15 +11,12 @@ use crate::rustc::hir; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; +use crate::syntax::ast::Ident; use crate::syntax::source_map::Span; use crate::utils::paths; -use crate::utils::{ - in_macro, match_trait_method, match_type, - remove_blocks, snippet, - span_lint_and_sugg, -}; +use crate::utils::{in_macro, match_trait_method, match_type, remove_blocks, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; -use crate::syntax::ast::Ident; #[derive(Clone)] pub struct Pass; @@ -95,13 +92,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { fn lint(cx: &LateContext<'_, '_>, replace: Span, root: Span, name: Ident, path: &hir::Expr) { if let hir::ExprKind::Path(hir::QPath::Resolved(None, ref path)) = path.node { if path.segments.len() == 1 && path.segments[0].ident == name { + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, MAP_CLONE, replace, "You are using an explicit closure for cloning elements", "Consider calling the dedicated `cloned` method", - format!("{}.cloned()", snippet(cx, root, "..")), + format!("{}.cloned()", snippet_with_applicability(cx, root, "..", &mut applicability)), + applicability, ) } } diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 9e2dac8fef1..583cdee843f 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -19,7 +19,7 @@ use crate::syntax::ast::LitKind; use crate::syntax::source_map::Span; use crate::utils::paths; use crate::utils::{expr_block, in_macro, is_allowed, is_expn_of, match_qpath, match_type, - multispan_sugg, remove_blocks, snippet, span_lint_and_sugg, span_lint_and_then, + multispan_sugg, remove_blocks, snippet, snippet_with_applicability, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty}; use crate::utils::sugg::Sugg; use crate::consts::{constant, Constant}; @@ -268,8 +268,9 @@ fn report_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms: snippet(cx, arms[0].pats[0].span, ".."), snippet(cx, ex.span, ".."), expr_block(cx, &arms[0].body, None, ".."), - els_str + els_str, ), + Applicability::HasPlaceholders, ); } @@ -477,13 +478,15 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: & }; if let Some(rb) = arm_ref { let suggestion = if rb == BindingAnnotation::Ref { "as_ref" } else { "as_mut" }; + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, MATCH_AS_REF, expr.span, &format!("use {}() instead", suggestion), "try this", - format!("{}.{}()", snippet(cx, ex.span, "_"), suggestion) + format!("{}.{}()", snippet_with_applicability(cx, ex.span, "_", &mut applicability), suggestion), + applicability, ) } } diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index ff57571a948..f0310b87f69 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -11,7 +11,8 @@ use crate::rustc::hir::{Expr, ExprKind, MutMutable, QPath}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; -use crate::utils::{match_def_path, match_qpath, opt_def_id, paths, snippet, span_lint_and_sugg}; +use crate::rustc_errors::Applicability; +use crate::utils::{match_def_path, match_qpath, opt_def_id, paths, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; /// **What it does:** Checks for `mem::replace()` on an `Option` with @@ -79,13 +80,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemReplace { _ => return, }; + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, MEM_REPLACE_OPTION_WITH_NONE, expr.span, "replacing an `Option` with `None`", "consider `Option::take()` instead", - format!("{}.take()", snippet(cx, replaced_path.span, "")) + format!("{}.take()", snippet_with_applicability(cx, replaced_path.span, "", &mut applicability)), + applicability, ); } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e3c704b77ad..dc939ad0815 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -22,8 +22,9 @@ use crate::utils::sugg; use crate::utils::{ get_arg_name, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, is_self, is_self_ty, iter_input_pats, last_path_segment, match_def_path, match_path, match_qpath, match_trait_method, match_type, - match_var, method_calls, method_chain_args, remove_blocks, return_ty, same_tys, single_segment_path, snippet, snippet_with_macro_callsite, span_lint, - span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, + match_var, method_calls, method_chain_args, remove_blocks, return_ty, same_tys, single_segment_path, snippet, + snippet_with_macro_callsite, snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then, + span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, }; use if_chain::if_chain; use matches::matches; @@ -1035,13 +1036,15 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa }; if implements_trait(cx, arg_ty, default_trait_id, &[]) { + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, OR_FUN_CALL, span, &format!("use of `{}` followed by a call to `{}`", name, path), "try this", - format!("{}.unwrap_or_default()", snippet(cx, self_expr.span, "_")), + format!("{}.unwrap_or_default()", snippet_with_applicability(cx, self_expr.span, "_", &mut applicability)), + applicability, ); return true; } @@ -1111,6 +1114,7 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa &format!("use of `{}` followed by a function call", name), "try this", format!("{}_{}({})", name, suffix, sugg), + Applicability::HasPlaceholders, ); } @@ -1153,11 +1157,15 @@ fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: None } - fn generate_format_arg_snippet(cx: &LateContext<'_, '_>, a: &hir::Expr) -> String { + fn generate_format_arg_snippet( + cx: &LateContext<'_, '_>, + a: &hir::Expr, + applicability: &mut Applicability, + ) -> String { if let hir::ExprKind::AddrOf(_, ref format_arg) = a.node { if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.node { if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.node { - return snippet(cx, format_arg_expr_tup[0].span, "..").into_owned(); + return snippet_with_applicability(cx, format_arg_expr_tup[0].span, "..", applicability).into_owned(); } } }; @@ -1208,11 +1216,12 @@ fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: let span_replace_word = method_span.with_hi(span.hi()); if let Some(format_args) = extract_format_args(arg) { + let mut applicability = Applicability::MachineApplicable; let args_len = format_args.len(); let args: Vec = format_args .into_iter() .take(args_len - 1) - .map(|a| generate_format_arg_snippet(cx, a)) + .map(|a| generate_format_arg_snippet(cx, a, &mut applicability)) .collect(); let sugg = args.join(", "); @@ -1224,12 +1233,14 @@ fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: &format!("use of `{}` followed by a function call", name), "try this", format!("unwrap_or_else({} panic!({}))", closure, sugg), + applicability, ); return; } - let sugg: Cow<'_, _> = snippet(cx, arg.span, ".."); + let mut applicability = Applicability::MachineApplicable; + let sugg: Cow<'_, _> = snippet_with_applicability(cx, arg.span, "..", &mut applicability); span_lint_and_sugg( cx, @@ -1238,6 +1249,7 @@ fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: &format!("use of `{}` followed by a function call", name), "try this", format!("unwrap_or_else({} {{ let msg = {}; panic!(msg) }}))", closure, sugg), + applicability, ); } @@ -1354,6 +1366,7 @@ fn lint_clone_on_ref_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir:: "using '.clone()' on a ref-counted pointer", "try this", format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet(cx, arg.span, "_")), + Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak ); } } @@ -1372,6 +1385,7 @@ fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::E return; }; + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, STRING_EXTEND_CHARS, @@ -1380,10 +1394,11 @@ fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::E "try this", format!( "{}.push_str({}{})", - snippet(cx, args[0].span, "_"), + snippet_with_applicability(cx, args[0].span, "_", &mut applicability), ref_str, - snippet(cx, target.span, "_") + snippet_with_applicability(cx, target.span, "_", &mut applicability) ), + applicability, ); } } @@ -1460,12 +1475,13 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args: let next_point = cx.sess().source_map().next_point(fold_args[0].span); let fold_span = next_point.with_hi(fold_args[2].span.hi() + BytePos(1)); + let mut applicability = Applicability::MachineApplicable; let sugg = if replacement_has_args { format!( ".{replacement}(|{s}| {r})", replacement = replacement_method_name, s = second_arg_ident, - r = snippet(cx, right_expr.span, "EXPR"), + r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), ) } else { format!( @@ -1482,6 +1498,7 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args: "this `.fold` can be written more succinctly using another method", "try", sugg, + applicability, ); } } @@ -1545,9 +1562,10 @@ fn lint_iter_nth(cx: &LateContext<'_, '_>, expr: &hir::Expr, iter_args: &[hir::E fn lint_get_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, get_args: &[hir::Expr], is_mut: bool) { // Note: we don't want to lint `get_mut().unwrap` for HashMap or BTreeMap, // because they do not implement `IndexMut` + let mut applicability = Applicability::MachineApplicable; let expr_ty = cx.tables.expr_ty(&get_args[0]); let get_args_str = if get_args.len() > 1 { - snippet(cx, get_args[1].span, "_") + snippet_with_applicability(cx, get_args[1].span, "_", &mut applicability) } else { return; // not linting on a .get().unwrap() chain or variant }; @@ -1586,9 +1604,10 @@ fn lint_get_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, get_args: &[hir:: format!( "{}{}[{}]", borrow_str, - snippet(cx, get_args[0].span, "_"), + snippet_with_applicability(cx, get_args[0].span, "_", &mut applicability), get_args_str ), + applicability, ); } @@ -2004,22 +2023,26 @@ fn lint_chars_cmp( if let Some(segment) = single_segment_path(qpath); if segment.ident.name == "Some"; then { + let mut applicability = Applicability::MachineApplicable; let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0])); if self_ty.sty != ty::Str { return false; } - span_lint_and_sugg(cx, - lint, - info.expr.span, - &format!("you should use the `{}` method", suggest), - "like this", - format!("{}{}.{}({})", - if info.eq { "" } else { "!" }, - snippet(cx, args[0][0].span, "_"), - suggest, - snippet(cx, arg_char[0].span, "_"))); + span_lint_and_sugg( + cx, + lint, + info.expr.span, + &format!("you should use the `{}` method", suggest), + "like this", + format!("{}{}.{}({})", + if info.eq { "" } else { "!" }, + snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability), + suggest, + snippet_with_applicability(cx, arg_char[0].span, "_", &mut applicability)), + applicability, + ); return true; } @@ -2035,10 +2058,10 @@ fn lint_chars_next_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprIn /// Checks for the `CHARS_LAST_CMP` lint. fn lint_chars_last_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool { - if lint_chars_cmp(cx, info, &["chars", "last"], CHARS_NEXT_CMP, "ends_with") { + if lint_chars_cmp(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") { true } else { - lint_chars_cmp(cx, info, &["chars", "next_back"], CHARS_NEXT_CMP, "ends_with") + lint_chars_cmp(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with") } } @@ -2055,6 +2078,7 @@ fn lint_chars_cmp_with_unwrap<'a, 'tcx>( if let hir::ExprKind::Lit(ref lit) = info.other.node; if let ast::LitKind::Char(c) = lit.node; then { + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, lint, @@ -2063,9 +2087,10 @@ fn lint_chars_cmp_with_unwrap<'a, 'tcx>( "like this", format!("{}{}.{}('{}')", if info.eq { "" } else { "!" }, - snippet(cx, args[0][0].span, "_"), + snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability), suggest, - c) + c), + applicability, ); return true; @@ -2096,7 +2121,8 @@ fn lint_single_char_pattern<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, _expr: &'tcx h if let ast::LitKind::Str(r, _) = lit.node; if r.as_str().len() == 1; then { - let snip = snippet(cx, arg.span, ".."); + let mut applicability = Applicability::MachineApplicable; + let snip = snippet_with_applicability(cx, arg.span, "..", &mut applicability); let hint = format!("'{}'", &snip[1..snip.len() - 1]); span_lint_and_sugg( cx, @@ -2105,6 +2131,7 @@ fn lint_single_char_pattern<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, _expr: &'tcx h "single-character string constant used as pattern", "try using a char instead", hint, + applicability, ); } } @@ -2122,13 +2149,15 @@ fn lint_asref(cx: &LateContext<'_, '_>, expr: &hir::Expr, call_name: &str, as_re let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty); let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty); if base_rcv_ty == base_res_ty && rcv_depth >= res_depth { + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, USELESS_ASREF, expr.span, &format!("this call to `{}` does nothing", call_name), "try this", - snippet(cx, recvr.span, "_").into_owned(), + snippet_with_applicability(cx, recvr.span, "_", &mut applicability).to_string(), + applicability, ); } } @@ -2193,7 +2222,8 @@ fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: ty::T kind, ), "call directly", - method_name.to_owned(), + method_name.to_string(), + Applicability::MachineApplicable, ); } } diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 0019380a34c..37ccf28d572 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -12,13 +12,14 @@ //! //! This lint is **warn** by default +use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; -use crate::rustc::hir::*; +use crate::rustc_errors::Applicability; use crate::syntax::ast::LitKind; use crate::syntax::source_map::Spanned; -use crate::utils::{in_macro, snippet, span_lint, span_lint_and_sugg}; use crate::utils::sugg::Sugg; +use crate::utils::{in_macro, snippet_with_applicability, span_lint, span_lint_and_sugg}; /// **What it does:** Checks for expressions of the form `if c { true } else { /// false }` @@ -73,7 +74,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool { use self::Expression::*; if let ExprKind::If(ref pred, ref then_block, Some(ref else_expr)) = e.node { let reduce = |ret, not| { - let snip = Sugg::hir(cx, pred, ""); + let mut applicability = Applicability::MachineApplicable; + let snip = Sugg::hir_with_applicability(cx, pred, "", &mut applicability); let snip = if not { !snip } else { snip }; let hint = if ret { @@ -89,6 +91,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool { "this if-then-else expression returns a bool literal", "you can reduce it to", hint, + applicability, ); }; if let ExprKind::Block(ref then_block, _) = then_block.node { @@ -140,31 +143,34 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison { } if let ExprKind::Binary(Spanned { node: BinOpKind::Eq, .. }, ref left_side, ref right_side) = e.node { + let mut applicability = Applicability::MachineApplicable; match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) { (Bool(true), Other) => { - let hint = snippet(cx, right_side.span, "..").into_owned(); + let hint = snippet_with_applicability(cx, right_side.span, "..", &mut applicability); span_lint_and_sugg( cx, BOOL_COMPARISON, e.span, "equality checks against true are unnecessary", "try simplifying it as shown", - hint, + hint.to_string(), + applicability, ); }, (Other, Bool(true)) => { - let hint = snippet(cx, left_side.span, "..").into_owned(); + let hint = snippet_with_applicability(cx, left_side.span, "..", &mut applicability); span_lint_and_sugg( cx, BOOL_COMPARISON, e.span, "equality checks against true are unnecessary", "try simplifying it as shown", - hint, + hint.to_string(), + applicability, ); }, (Bool(false), Other) => { - let hint = Sugg::hir(cx, right_side, ".."); + let hint = Sugg::hir_with_applicability(cx, right_side, "..", &mut applicability); span_lint_and_sugg( cx, BOOL_COMPARISON, @@ -172,10 +178,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison { "equality checks against false can be replaced by a negation", "try simplifying it as shown", (!hint).to_string(), + applicability, ); }, (Other, Bool(false)) => { - let hint = Sugg::hir(cx, left_side, ".."); + let hint = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability); span_lint_and_sugg( cx, BOOL_COMPARISON, @@ -183,6 +190,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison { "equality checks against false can be replaced by a negation", "try simplifying it as shown", (!hint).to_string(), + applicability, ); }, _ => (), diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 289b5591edc..72ed649c5d9 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -8,10 +8,11 @@ // except according to those terms. -use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::hir::def::Def; use crate::rustc::hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; use crate::utils::{has_drop, in_macro, snippet_opt, span_lint, span_lint_and_sugg}; use std::ops::Deref; @@ -131,6 +132,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { "statement can be reduced", "replace it with", snippet, + Applicability::MachineApplicable, ); } } diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 1c5e8fcb964..d8f2645699d 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -10,9 +10,10 @@ use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; use crate::syntax::ast::*; use crate::syntax::source_map::Spanned; -use crate::utils::{in_macro, snippet, span_lint_and_sugg}; +use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg}; /// **What it does:** Checks for operations where precedence may be unclear /// and suggests to add parentheses. Currently it catches the following: @@ -53,7 +54,7 @@ impl EarlyLintPass for Precedence { } if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.node { - let span_sugg = |expr: &Expr, sugg| { + let span_sugg = |expr: &Expr, sugg, appl| { span_lint_and_sugg( cx, PRECEDENCE, @@ -61,39 +62,41 @@ impl EarlyLintPass for Precedence { "operator precedence can trip the unwary", "consider parenthesizing your expression", sugg, + appl, ); }; if !is_bit_op(op) { return; } + let mut applicability = Applicability::MachineApplicable; match (is_arith_expr(left), is_arith_expr(right)) { (true, true) => { let sugg = format!( "({}) {} ({})", - snippet(cx, left.span, ".."), + snippet_with_applicability(cx, left.span, "..", &mut applicability), op.to_string(), - snippet(cx, right.span, "..") + snippet_with_applicability(cx, right.span, "..", &mut applicability) ); - span_sugg(expr, sugg); + span_sugg(expr, sugg, applicability); }, (true, false) => { let sugg = format!( "({}) {} {}", - snippet(cx, left.span, ".."), + snippet_with_applicability(cx, left.span, "..", &mut applicability), op.to_string(), - snippet(cx, right.span, "..") + snippet_with_applicability(cx, right.span, "..", &mut applicability) ); - span_sugg(expr, sugg); + span_sugg(expr, sugg, applicability); }, (false, true) => { let sugg = format!( "{} {} ({})", - snippet(cx, left.span, ".."), + snippet_with_applicability(cx, left.span, "..", &mut applicability), op.to_string(), - snippet(cx, right.span, "..") + snippet_with_applicability(cx, right.span, "..", &mut applicability) ); - span_sugg(expr, sugg); + span_sugg(expr, sugg, applicability); }, (false, false) => (), } @@ -105,13 +108,15 @@ impl EarlyLintPass for Precedence { if let ExprKind::Lit(ref lit) = slf.node { match lit.node { LitKind::Int(..) | LitKind::Float(..) | LitKind::FloatUnsuffixed(..) => { + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, PRECEDENCE, expr.span, "unary minus has lower precedence than method call", "consider adding parentheses to clarify your intent", - format!("-({})", snippet(cx, rhs.span, "..")), + format!("-({})", snippet_with_applicability(cx, rhs.span, "..", &mut applicability)), + applicability, ); }, _ => (), diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 58afdc351d1..0d37d4d4b08 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -9,6 +9,7 @@ use crate::rustc::{declare_tool_lint, hir, lint, lint_array}; +use crate::rustc_errors::Applicability; use crate::utils; use std::fmt; @@ -69,7 +70,15 @@ impl<'a, 'tcx> lint::LateLintPass<'a, 'tcx> for Pass { let msg = format!("use of `{}` with a `usize` casted to an `isize`", method); if let Some(sugg) = build_suggestion(cx, method, receiver_expr, cast_lhs_expr) { - utils::span_lint_and_sugg(cx, PTR_OFFSET_WITH_CAST, expr.span, &msg, "try", sugg); + utils::span_lint_and_sugg( + cx, + PTR_OFFSET_WITH_CAST, + expr.span, + &msg, + "try", + sugg, + Applicability::MachineApplicable, + ); } else { utils::span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, &msg); } diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs index 526232f7853..b25ea1d5d38 100644 --- a/clippy_lints/src/redundant_field_names.rs +++ b/clippy_lints/src/redundant_field_names.rs @@ -10,6 +10,7 @@ use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; use crate::syntax::ast::*; use crate::utils::{span_lint_and_sugg}; @@ -58,13 +59,14 @@ impl EarlyLintPass for RedundantFieldNames { } if let ExprKind::Path(None, path) = &field.expr.node { if path.segments.len() == 1 && path.segments[0].ident == field.ident { - span_lint_and_sugg ( + span_lint_and_sugg( cx, REDUNDANT_FIELD_NAMES, field.span, "redundant field names in struct initialization", "replace it with", - field.ident.to_string() + field.ident.to_string(), + Applicability::MachineApplicable, ); } } diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 79d30612cbd..7651c6f0a9f 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -8,11 +8,12 @@ // except according to those terms. -use crate::syntax::ast::{Expr, ExprKind, UnOp}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; +use crate::syntax::ast::{Expr, ExprKind, UnOp}; +use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; -use crate::utils::{snippet, span_lint_and_sugg}; /// **What it does:** Checks for usage of `*&` and `*&mut` in expressions. /// @@ -54,13 +55,15 @@ impl EarlyLintPass for Pass { if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.node; if let ExprKind::AddrOf(_, ref addrof_target) = without_parens(deref_target).node; then { + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, DEREF_ADDROF, e.span, "immediately dereferencing a reference", "try this", - format!("{}", snippet(cx, addrof_target.span, "_")), + format!("{}", snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability)), + applicability, ); } } @@ -100,6 +103,7 @@ impl EarlyLintPass for DerefPass { if let ExprKind::Paren(ref parened) = object.node; if let ExprKind::AddrOf(_, ref inner) = parened.node; then { + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, REF_IN_DEREF, @@ -108,9 +112,10 @@ impl EarlyLintPass for DerefPass { "try this", format!( "{}.{}", - snippet(cx, inner.span, "_"), - snippet(cx, field_name.span, "_") - ) + snippet_with_applicability(cx, inner.span, "_", &mut applicability), + snippet_with_applicability(cx, field_name.span, "_", &mut applicability) + ), + applicability, ); } } diff --git a/clippy_lints/src/replace_consts.rs b/clippy_lints/src/replace_consts.rs index ca17a032526..e3016b7259b 100644 --- a/clippy_lints/src/replace_consts.rs +++ b/clippy_lints/src/replace_consts.rs @@ -8,12 +8,13 @@ // except according to those terms. -use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use crate::rustc::{declare_tool_lint, lint_array}; -use if_chain::if_chain; use crate::rustc::hir; use crate::rustc::hir::def::Def; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; use crate::utils::{match_def_path, span_lint_and_sugg}; +use if_chain::if_chain; /// **What it does:** Checks for usage of `ATOMIC_X_INIT`, `ONCE_INIT`, and /// `uX/iX::MIN/MAX`. @@ -61,6 +62,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ReplaceConsts { &format!("using `{}`", const_path.last().expect("empty path")), "try this", repl_snip.to_string(), + Applicability::MachineApplicable, ); return; } diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index e07b1649a46..05d64fbcd04 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -10,6 +10,7 @@ use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; use crate::syntax::source_map::Spanned; use crate::utils::SpanlessEq; use crate::utils::{get_parent_expr, is_allowed, match_type, paths, span_lint, span_lint_and_sugg, walk_ptrs_ty}; @@ -164,7 +165,7 @@ impl LintPass for StringLitAsBytes { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { use crate::syntax::ast::{LitKind, StrStyle}; - use crate::utils::{in_macro, snippet}; + use crate::utils::{in_macro, snippet, snippet_with_applicability}; if let ExprKind::MethodCall(ref path, _, ref args) = e.node { if path.ident.name == "as_bytes" { @@ -177,6 +178,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { } else { format!("\"{}\"", lit_content.as_str()) }; + let mut applicability = Applicability::MachineApplicable; if callsite.starts_with("include_str!") { span_lint_and_sugg( cx, @@ -184,7 +186,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { e.span, "calling `as_bytes()` on `include_str!(..)`", "consider using `include_bytes!(..)` instead", - snippet(cx, args[0].span, r#""foo""#).replacen("include_str", "include_bytes", 1), + snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen( + "include_str", + "include_bytes", + 1, + ), + applicability, ); } else if callsite == expanded && lit_content.as_str().chars().all(|c| c.is_ascii()) @@ -196,7 +203,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes { e.span, "calling `as_bytes()` on a string literal", "consider using a byte string literal instead", - format!("b{}", snippet(cx, args[0].span, r#""foo""#)), + format!( + "b{}", + snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability) + ), + applicability, ); } } diff --git a/clippy_lints/src/trivially_copy_pass_by_ref.rs b/clippy_lints/src/trivially_copy_pass_by_ref.rs index 2929752bbb2..836f84e8966 100644 --- a/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -10,21 +10,21 @@ use std::cmp; -use matches::matches; use crate::rustc::hir; -use crate::rustc::hir::*; use crate::rustc::hir::intravisit::FnKind; +use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use crate::rustc::{declare_tool_lint, lint_array}; -use if_chain::if_chain; -use crate::rustc::ty::TyKind; -use crate::rustc::ty::FnSig; use crate::rustc::session::config::Config as SessionConfig; -use crate::rustc_target::spec::abi::Abi; +use crate::rustc::ty::{FnSig, TyKind}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; use crate::rustc_target::abi::LayoutOf; +use crate::rustc_target::spec::abi::Abi; use crate::syntax::ast::NodeId; use crate::syntax_pos::Span; -use crate::utils::{in_macro, is_copy, is_self_ty, span_lint_and_sugg, snippet}; +use crate::utils::{in_macro, is_copy, is_self_ty, snippet, span_lint_and_sugg}; +use if_chain::if_chain; +use matches::matches; /// **What it does:** Checks for functions taking arguments by reference, where /// the argument type is `Copy` and small enough to be more efficient to always @@ -141,7 +141,9 @@ impl<'a, 'tcx> TriviallyCopyPassByRef { input.span, "this argument is passed by reference, but would be more efficient if passed by value", "consider passing by value instead", - value_type); + value_type, + Applicability::Unspecified, + ); } } } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index d7adcd17981..61f294e1f3c 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -10,28 +10,31 @@ #![allow(clippy::default_hash_types)] +use crate::consts::{constant, Constant}; use crate::reexport::*; use crate::rustc::hir; -use crate::rustc::hir::*; use crate::rustc::hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; -use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; -use crate::rustc::{declare_tool_lint, lint_array}; -use if_chain::if_chain; -use crate::rustc::ty::{self, Ty, TyCtxt, TypeckTables}; +use crate::rustc::hir::*; +use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass}; use crate::rustc::ty::layout::LayoutOf; +use crate::rustc::ty::{self, Ty, TyCtxt, TypeckTables}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; +use crate::rustc_target::spec::abi::Abi; use crate::rustc_typeck::hir_ty_to_ty; +use crate::syntax::ast::{FloatTy, IntTy, UintTy}; +use crate::syntax::errors::DiagnosticBuilder; +use crate::syntax::source_map::Span; +use crate::utils::paths; +use crate::utils::{ + clip, comparisons, differing_macro_contexts, higher, in_constant, in_macro, int_bits, last_path_segment, + match_def_path, match_path, match_type, multispan_sugg, opt_def_id, same_tys, sext, snippet, snippet_opt, + snippet_with_applicability, span_help_and_lint, span_lint, span_lint_and_sugg, span_lint_and_then, unsext, +}; +use if_chain::if_chain; +use std::borrow::Cow; use std::cmp::Ordering; use std::collections::BTreeMap; -use std::borrow::Cow; -use crate::syntax::ast::{FloatTy, IntTy, UintTy}; -use crate::syntax::source_map::Span; -use crate::syntax::errors::DiagnosticBuilder; -use crate::rustc_target::spec::abi::Abi; -use crate::utils::{comparisons, differing_macro_contexts, higher, in_constant, in_macro, last_path_segment, match_def_path, match_path, - match_type, multispan_sugg, opt_def_id, same_tys, snippet, snippet_opt, span_help_and_lint, span_lint, - span_lint_and_sugg, span_lint_and_then, clip, unsext, sext, int_bits}; -use crate::utils::paths; -use crate::consts::{constant, Constant}; /// Handles all the linting of funky types pub struct TypePass; @@ -331,19 +334,22 @@ fn check_ty_rptr(cx: &LateContext<'_, '_>, ast_ty: &hir::Ty, is_local: bool, lt: let ltopt = if lt.is_elided() { String::new() } else { - format!("{} ", lt.name.ident().name.as_str()) + format!("{} ", lt.name.ident().as_str()) }; let mutopt = if mut_ty.mutbl == Mutability::MutMutable { "mut " } else { "" }; - span_lint_and_sugg(cx, + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, BORROWED_BOX, ast_ty.span, "you seem to be trying to use `&Box`. Consider using just `&T`", "try", - format!("&{}{}{}", ltopt, mutopt, &snippet(cx, inner.span, "..")) + format!("&{}{}{}", ltopt, mutopt, &snippet_with_applicability(cx, inner.span, "..", &mut applicability)), + Applicability::Unspecified, ); return; // don't recurse into the type } @@ -537,6 +543,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg { "passing a unit value to a function", "if you intended to pass a unit value, use a unit literal instead", "()".to_string(), + Applicability::MachineApplicable, ); } } @@ -856,6 +863,7 @@ fn span_lossless_lint(cx: &LateContext<'_, '_>, expr: &Expr, op: &Expr, cast_fro if in_constant(cx, expr.id) { return } // The suggestion is to use a function call, so if the original expression // has parens on the outside, they are no longer needed. + let mut applicability = Applicability::MachineApplicable; let opt = snippet_opt(cx, op.span); let sugg = if let Some(ref snip) = opt { if should_strip_parens(op, snip) { @@ -864,6 +872,7 @@ fn span_lossless_lint(cx: &LateContext<'_, '_>, expr: &Expr, op: &Expr, cast_fro snip.as_str() } } else { + applicability = Applicability::HasPlaceholders; ".." }; @@ -874,6 +883,7 @@ fn span_lossless_lint(cx: &LateContext<'_, '_>, expr: &Expr, op: &Expr, cast_fro &format!("casting {} to {} may become silently lossy if types change", cast_from, cast_to), "try", format!("{}::from({})", cast_to, sugg), + applicability, ); } @@ -1093,7 +1103,8 @@ fn lint_fn_to_numeric_cast(cx: &LateContext<'_, '_>, expr: &Expr, cast_expr: &Ex } match cast_from.sty { ty::FnDef(..) | ty::FnPtr(_) => { - let from_snippet = snippet(cx, cast_expr.span, "x"); + let mut applicability = Applicability::MachineApplicable; + let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); let to_nbits = int_ty_to_nbits(cast_to, cx.tcx); if to_nbits < cx.tcx.data_layout.pointer_size.bits() { @@ -1103,7 +1114,8 @@ fn lint_fn_to_numeric_cast(cx: &LateContext<'_, '_>, expr: &Expr, cast_expr: &Ex expr.span, &format!("casting function pointer `{}` to `{}`, which truncates the value", from_snippet, cast_to), "try", - format!("{} as usize", from_snippet) + format!("{} as usize", from_snippet), + applicability, ); } else if cast_to.sty != ty::Uint(UintTy::Usize) { @@ -1113,7 +1125,8 @@ fn lint_fn_to_numeric_cast(cx: &LateContext<'_, '_>, expr: &Expr, cast_expr: &Ex expr.span, &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to), "try", - format!("{} as usize", from_snippet) + format!("{} as usize", from_snippet), + applicability, ); } }, diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index ad4ced995ba..564bdb0bb03 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -8,15 +8,16 @@ // except according to those terms. -use crate::utils::{in_macro, span_lint_and_sugg}; -use if_chain::if_chain; use crate::rustc::hir::intravisit::{walk_path, walk_ty, NestedVisitorMap, Visitor}; use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::ty; use crate::rustc::{declare_tool_lint, lint_array}; -use crate::syntax_pos::symbol::keywords::SelfType; +use crate::rustc_errors::Applicability; use crate::syntax::ast::NodeId; +use crate::syntax_pos::symbol::keywords::SelfType; +use crate::utils::{in_macro, span_lint_and_sugg}; +use if_chain::if_chain; /// **What it does:** Checks for unnecessary repetition of structure name when a /// replacement with `Self` is applicable. @@ -70,6 +71,7 @@ fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path) { "unnecessary structure name repetition", "use the applicable keyword", "Self".to_owned(), + Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 879157ec8a4..fd232e2a366 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -18,6 +18,7 @@ use crate::rustc::hir::*; use crate::rustc::hir::def::Def; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet}; use crate::syntax::ast::{Crate as AstCrate, Ident, ItemKind, Name}; use crate::syntax::source_map::Span; @@ -281,6 +282,7 @@ impl EarlyLintPass for DefaultHashTypes { &msg, "use", replace.to_string(), + Applicability::MaybeIncorrect, // FxHashMap, ... needs another import ); } } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 457aa3f8500..0c6935d867d 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -7,44 +7,48 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - use crate::reexport::*; -use matches::matches; -use if_chain::if_chain; use crate::rustc::hir; -use crate::rustc::hir::*; -use crate::rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use crate::rustc::hir::def::Def; +use crate::rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use crate::rustc::hir::intravisit::{NestedVisitorMap, Visitor}; use crate::rustc::hir::Node; +use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, Level, Lint, LintContext}; use crate::rustc::session::Session; use crate::rustc::traits; -use crate::rustc::ty::{self, Binder, Ty, TyCtxt, layout::{self, IntegerExt}, subst::Kind}; +use crate::rustc::ty::{ + self, + layout::{self, IntegerExt}, + subst::Kind, + Binder, Ty, TyCtxt, +}; use crate::rustc_errors::{Applicability, CodeSuggestion, Substitution, SubstitutionPart}; +use crate::syntax::ast::{self, LitKind}; +use crate::syntax::attr; +use crate::syntax::errors::DiagnosticBuilder; +use crate::syntax::source_map::{Span, DUMMY_SP}; +use crate::syntax::symbol::{keywords, Symbol}; +use if_chain::if_chain; +use matches::matches; use std::borrow::Cow; use std::env; use std::mem; -use std::str::FromStr; use std::rc::Rc; -use crate::syntax::ast::{self, LitKind}; -use crate::syntax::attr; -use crate::syntax::source_map::{Span, DUMMY_SP}; -use crate::syntax::errors::DiagnosticBuilder; -use crate::syntax::symbol::{keywords, Symbol}; +use std::str::FromStr; pub mod camel_case; +pub mod author; pub mod comparisons; pub mod conf; pub mod constants; mod hir_utils; -pub mod paths; -pub mod sugg; pub mod inspector; pub mod internal_lints; -pub mod author; +pub mod paths; pub mod ptr; +pub mod sugg; pub mod usage; pub use self::hir_utils::{SpanlessEq, SpanlessHash}; @@ -101,11 +105,7 @@ pub fn match_def_path(tcx: TyCtxt<'_, '_, '_>, def_id: DefId, path: &[&str]) -> tcx.push_item_path(&mut apb, def_id, false); - apb.names.len() == path.len() - && apb.names - .into_iter() - .zip(path.iter()) - .all(|(a, &b)| *a == *b) + apb.names.len() == path.len() && apb.names.into_iter().zip(path.iter()).all(|(a, &b)| *a == *b) } /// Check if type is struct, enum or union type with given def path. @@ -137,12 +137,9 @@ pub fn match_var(expr: &Expr, var: Name) -> bool { false } - pub fn last_path_segment(path: &QPath) -> &PathSegment { match *path { - QPath::Resolved(_, ref path) => path.segments - .last() - .expect("A path must have at least one segment"), + QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"), QPath::TypeRelative(_, ref seg) => seg, } } @@ -166,7 +163,8 @@ pub fn match_qpath(path: &QPath, segments: &[&str]) -> bool { QPath::Resolved(_, ref path) => match_path(path, segments), QPath::TypeRelative(ref ty, ref segment) => match ty.node { TyKind::Path(ref inner_path) => { - !segments.is_empty() && match_qpath(inner_path, &segments[..(segments.len() - 1)]) + !segments.is_empty() + && match_qpath(inner_path, &segments[..(segments.len() - 1)]) && segment.ident.name == segments[segments.len() - 1] }, _ => false, @@ -199,9 +197,7 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { /// Get the definition associated to a path. pub fn path_to_def(cx: &LateContext<'_, '_>, path: &[&str]) -> Option { let crates = cx.tcx.crates(); - let krate = crates - .iter() - .find(|&&krate| cx.tcx.crate_name(krate) == path[0]); + let krate = crates.iter().find(|&&krate| cx.tcx.crate_name(krate) == path[0]); if let Some(krate) = krate { let krate = DefId { krate: *krate, @@ -254,10 +250,17 @@ pub fn implements_trait<'a, 'tcx>( ty_params: &[Kind<'tcx>], ) -> bool { let ty = cx.tcx.erase_regions(&ty); - let obligation = - cx.tcx - .predicate_for_trait_def(cx.param_env, traits::ObligationCause::dummy(), trait_id, 0, ty, ty_params); - cx.tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold(&obligation)) + let obligation = cx.tcx.predicate_for_trait_def( + cx.param_env, + traits::ObligationCause::dummy(), + trait_id, + 0, + ty, + ty_params, + ); + cx.tcx + .infer_ctxt() + .enter(|infcx| infcx.predicate_must_hold(&obligation)) } /// Check whether this type implements Drop. @@ -326,14 +329,14 @@ pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option, expr: &Expr) -> Option { let parent_id = cx.tcx.hir.get_parent(expr.id); match cx.tcx.hir.find(parent_id) { Some(Node::Item(&Item { ref name, .. })) => Some(*name), - Some(Node::TraitItem(&TraitItem { ident, .. })) | - Some(Node::ImplItem(&ImplItem { ident, .. })) => Some(ident.name), + Some(Node::TraitItem(&TraitItem { ident, .. })) | Some(Node::ImplItem(&ImplItem { ident, .. })) => { + Some(ident.name) + }, _ => None, } } @@ -366,15 +369,11 @@ impl<'tcx> Visitor<'tcx> for ContainsName { /// check if an `Expr` contains a certain name pub fn contains_name(name: Name, expr: &Expr) -> bool { - let mut cn = ContainsName { - name, - result: false, - }; + let mut cn = ContainsName { name, result: false }; cn.visit_expr(expr); cn.result } - /// Convert a span to a code snippet if available, otherwise use default. /// /// # Example @@ -385,6 +384,32 @@ pub fn snippet<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'a str) snippet_opt(cx, span).map_or_else(|| Cow::Borrowed(default), From::from) } +/// Same as `snippet`, but it adapts the applicability level by following rules: +/// +/// - Applicability level `Unspecified` will never be changed. +/// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`. +/// - If the default value is used and the applicability level is `MachineApplicable`, change it to +/// `HasPlaceholders` +pub fn snippet_with_applicability<'a, 'b, T: LintContext<'b>>( + cx: &T, + span: Span, + default: &'a str, + applicability: &mut Applicability, +) -> Cow<'a, str> { + if *applicability != Applicability::Unspecified && in_macro(span) { + *applicability = Applicability::MaybeIncorrect; + } + snippet_opt(cx, span).map_or_else( + || { + if *applicability == Applicability::MachineApplicable { + *applicability = Applicability::HasPlaceholders; + } + Cow::Borrowed(default) + }, + From::from, + ) +} + /// Same as `snippet`, but should only be used when it's clear that the input span is /// not a macro argument. pub fn snippet_with_macro_callsite<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> { @@ -411,6 +436,18 @@ pub fn snippet_block<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &' trim_multiline(snip, true) } +/// Same as `snippet_block`, but adapts the applicability level by the rules of +/// `snippet_with_applicabiliy`. +pub fn snippet_block_with_applicability<'a, 'b, T: LintContext<'b>>( + cx: &T, + span: Span, + default: &'a str, + applicability: &mut Applicability, +) -> Cow<'a, str> { + let snip = snippet_with_applicability(cx, span, default, applicability); + trim_multiline(snip, true) +} + /// Returns a new Span that covers the full last line of the given Span pub fn last_line_of_span<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Span { let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap(); @@ -431,8 +468,7 @@ pub fn expr_block<'a, 'b, T: LintContext<'b>>( let string = option.unwrap_or_default(); if in_macro(expr.span) { Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default))) - } - else if let ExprKind::Block(_, _) = expr.node { + } else if let ExprKind::Block(_, _) = expr.node { Cow::Owned(format!("{}{}", code, string)) } else if string.is_empty() { Cow::Owned(format!("{{ {} }}", code)) @@ -450,19 +486,15 @@ pub fn trim_multiline(s: Cow<'_, str>, ignore_first: bool) -> Cow<'_, str> { } fn trim_multiline_inner(s: Cow<'_, str>, ignore_first: bool, ch: char) -> Cow<'_, str> { - let x = s.lines() + let x = s + .lines() .skip(ignore_first as usize) .filter_map(|l| { if l.is_empty() { None } else { // ignore empty lines - Some( - l.char_indices() - .find(|&(_, x)| x != ch) - .unwrap_or((l.len(), ch)) - .0, - ) + Some(l.char_indices().find(|&(_, x)| x != ch).unwrap_or((l.len(), ch)).0) } }) .min() @@ -505,7 +537,8 @@ pub fn get_parent_expr<'c>(cx: &'c LateContext<'_, '_>, e: &Expr) -> Option<&'c pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeId) -> Option<&'tcx Block> { let map = &cx.tcx.hir; - let enclosing_node = map.get_enclosing_scope(node) + let enclosing_node = map + .get_enclosing_scope(node) .and_then(|enclosing_id| map.find(enclosing_id)); if let Some(node) = enclosing_node { match node { @@ -513,7 +546,8 @@ pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeI Node::Item(&Item { node: ItemKind::Fn(_, _, _, eid), .. - }) | Node::ImplItem(&ImplItem { + }) + | Node::ImplItem(&ImplItem { node: ImplItemKind::Method(_, eid), .. }) => match cx.tcx.hir.body(eid).value.node { @@ -617,7 +651,8 @@ pub fn span_lint_node_and_then( /// Add a span lint with a suggestion on how to fix it. /// /// These suggestions can be parsed by rustfix to allow it to automatically fix your code. -/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x > 2)"`. +/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x > +/// 2)"`. /// /// ```ignore /// error: This `.fold` can be more succinctly expressed as `.any` @@ -635,9 +670,10 @@ pub fn span_lint_and_sugg<'a, 'tcx: 'a, T: LintContext<'tcx>>( msg: &str, help: &str, sugg: String, + applicability: Applicability, ) { span_lint_and_then(cx, lint, sp, msg, |db| { - db.span_suggestion_with_applicability(sp, help, sugg, Applicability::Unspecified); + db.span_suggestion_with_applicability(sp, help, sugg, applicability); }); } @@ -652,18 +688,12 @@ where I: IntoIterator, { let sugg = CodeSuggestion { - substitutions: vec![ - Substitution { - parts: sugg.into_iter() - .map(|(span, snippet)| { - SubstitutionPart { - snippet, - span, - } - }) - .collect(), - } - ], + substitutions: vec![Substitution { + parts: sugg + .into_iter() + .map(|(span, snippet)| SubstitutionPart { snippet, span }) + .collect(), + }], msg: help_msg, show_code_when_inline: true, applicability: Applicability::Unspecified, @@ -729,9 +759,7 @@ impl LimitStack { Self { stack: vec![limit] } } pub fn limit(&self) -> u64 { - *self.stack - .last() - .expect("there should always be a value in the stack") + *self.stack.last().expect("there should always be a value in the stack") } pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { let stack = &mut self.stack; @@ -744,10 +772,11 @@ impl LimitStack { } pub fn get_attr<'a>(attrs: &'a [ast::Attribute], name: &'static str) -> impl Iterator { - attrs.iter().filter(move |attr| - attr.path.segments.len() == 2 && - attr.path.segments[0].ident.to_string() == "clippy" && - attr.path.segments[1].ident.to_string() == name) + attrs.iter().filter(move |attr| { + attr.path.segments.len() == 2 + && attr.path.segments[0].ident.to_string() == "clippy" + && attr.path.segments[1].ident.to_string() == name + }) } fn parse_attrs(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) { @@ -769,7 +798,8 @@ fn parse_attrs(sess: &Session, attrs: &[ast::Attribute], name: &' /// See also `is_direct_expn_of`. pub fn is_expn_of(mut span: Span, name: &str) -> Option { loop { - let span_name_span = span.ctxt() + let span_name_span = span + .ctxt() .outer() .expn_info() .map(|ei| (ei.format.name(), ei.call_site)); @@ -792,7 +822,8 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option { /// `bar!` by /// `is_direct_expn_of`. pub fn is_direct_expn_of(span: Span, name: &str) -> Option { - let span_name_span = span.ctxt() + let span_name_span = span + .ctxt() .outer() .expn_info() .map(|ei| (ei.format.name(), ei.call_site)); @@ -855,23 +886,23 @@ pub fn is_refutable(cx: &LateContext<'_, '_>, pat: &Pat) -> bool { PatKind::Lit(..) | PatKind::Range(..) => true, PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id), PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)), - PatKind::Struct(ref qpath, ref fields, _) => if is_enum_variant(cx, qpath, pat.hir_id) { - true - } else { - are_refutable(cx, fields.iter().map(|field| &*field.node.pat)) + PatKind::Struct(ref qpath, ref fields, _) => { + if is_enum_variant(cx, qpath, pat.hir_id) { + true + } else { + are_refutable(cx, fields.iter().map(|field| &*field.node.pat)) + } }, - PatKind::TupleStruct(ref qpath, ref pats, _) => if is_enum_variant(cx, qpath, pat.hir_id) { - true - } else { - are_refutable(cx, pats.iter().map(|pat| &**pat)) + PatKind::TupleStruct(ref qpath, ref pats, _) => { + if is_enum_variant(cx, qpath, pat.hir_id) { + true + } else { + are_refutable(cx, pats.iter().map(|pat| &**pat)) + } + }, + PatKind::Slice(ref head, ref middle, ref tail) => { + are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat)) }, - PatKind::Slice(ref head, ref middle, ref tail) => are_refutable( - cx, - head.iter() - .chain(middle) - .chain(tail.iter()) - .map(|pat| &**pat), - ), } } @@ -903,32 +934,37 @@ pub fn remove_blocks(expr: &Expr) -> &Expr { pub fn opt_def_id(def: Def) -> Option { match def { - Def::Fn(id) | - Def::Mod(id) | - Def::Static(id, _) | - Def::Variant(id) | - Def::VariantCtor(id, ..) | - Def::Enum(id) | - Def::TyAlias(id) | - Def::AssociatedTy(id) | - Def::TyParam(id) | - Def::ForeignTy(id) | - Def::Struct(id) | - Def::StructCtor(id, ..) | - Def::Union(id) | - Def::Trait(id) | - Def::TraitAlias(id) | - Def::Method(id) | - Def::Const(id) | - Def::AssociatedConst(id) | - Def::Macro(id, ..) | - Def::Existential(id) | - Def::AssociatedExistential(id) | - Def::SelfCtor(id) - => Some(id), + Def::Fn(id) + | Def::Mod(id) + | Def::Static(id, _) + | Def::Variant(id) + | Def::VariantCtor(id, ..) + | Def::Enum(id) + | Def::TyAlias(id) + | Def::AssociatedTy(id) + | Def::TyParam(id) + | Def::ForeignTy(id) + | Def::Struct(id) + | Def::StructCtor(id, ..) + | Def::Union(id) + | Def::Trait(id) + | Def::TraitAlias(id) + | Def::Method(id) + | Def::Const(id) + | Def::AssociatedConst(id) + | Def::Macro(id, ..) + | Def::Existential(id) + | Def::AssociatedExistential(id) + | Def::SelfCtor(id) => Some(id), - Def::Upvar(..) | Def::Local(_) | Def::Label(..) | Def::PrimTy(..) | Def::SelfTy(..) | - Def::ToolMod | Def::NonMacroAttr{..} | Def::Err => None, + Def::Upvar(..) + | Def::Local(_) + | Def::Label(..) + | Def::PrimTy(..) + | Def::SelfTy(..) + | Def::ToolMod + | Def::NonMacroAttr { .. } + | Def::Err => None, } } @@ -1019,7 +1055,9 @@ pub fn get_arg_name(pat: &Pat) -> Option { } pub fn int_bits(tcx: TyCtxt<'_, '_, '_>, ity: ast::IntTy) -> u64 { - layout::Integer::from_attr(&tcx, attr::IntType::SignedInt(ity)).size().bits() + layout::Integer::from_attr(&tcx, attr::IntType::SignedInt(ity)) + .size() + .bits() } #[allow(clippy::cast_possible_wrap)] @@ -1038,7 +1076,9 @@ pub fn unsext(tcx: TyCtxt<'_, '_, '_>, u: i128, ity: ast::IntTy) -> u128 { /// clip unused bytes pub fn clip(tcx: TyCtxt<'_, '_, '_>, u: u128, ity: ast::UintTy) -> u128 { - let bits = layout::Integer::from_attr(&tcx, attr::IntType::UnsignedInt(ity)).size().bits(); + let bits = layout::Integer::from_attr(&tcx, attr::IntType::UnsignedInt(ity)) + .size() + .bits(); let amt = 128 - bits; (u << amt) >> amt } diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 90f48f0f83c..b4c9868bbd6 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -24,7 +24,7 @@ use crate::syntax::parse::token; use crate::syntax::print::pprust::token_to_string; use crate::syntax::util::parser::AssocOp; use crate::syntax::ast; -use crate::utils::{higher, snippet, snippet_opt}; +use crate::utils::{higher, in_macro, snippet, snippet_opt}; use crate::syntax_pos::{BytePos, Pos}; use crate::rustc_errors::Applicability; @@ -96,6 +96,29 @@ impl<'a> Sugg<'a> { Self::hir_opt(cx, expr).unwrap_or_else(|| Sugg::NonParen(Cow::Borrowed(default))) } + /// Same as `hir`, but it adapts the applicability level by following rules: + /// + /// - Applicability level `Unspecified` will never be changed. + /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`. + /// - If the default value is used and the applicability level is `MachineApplicable`, change it to + /// `HasPlaceholders` + pub fn hir_with_applicability( + cx: &LateContext<'_, '_>, + expr: &hir::Expr, + default: &'a str, + applicability: &mut Applicability, + ) -> Self { + if *applicability != Applicability::Unspecified && in_macro(expr.span) { + *applicability = Applicability::MaybeIncorrect; + } + Self::hir_opt(cx, expr).unwrap_or_else(|| { + if *applicability == Applicability::MachineApplicable { + *applicability = Applicability::HasPlaceholders; + } + Sugg::NonParen(Cow::Borrowed(default)) + }) + } + /// Prepare a suggestion from an expression. pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self { use crate::syntax::ast::RangeLimits; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 21a33bd143f..d7e7de06355 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -8,14 +8,15 @@ // except according to those terms. +use crate::consts::constant; use crate::rustc::hir::*; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use crate::rustc::{declare_tool_lint, lint_array}; -use if_chain::if_chain; use crate::rustc::ty::{self, Ty}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; use crate::syntax::source_map::Span; -use crate::utils::{higher, is_copy, snippet, span_lint_and_sugg}; -use crate::consts::constant; +use crate::utils::{higher, is_copy, snippet_with_applicability, span_lint_and_sugg}; +use if_chain::if_chain; /// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would /// be possible. @@ -76,10 +77,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecArgs<'tcx>, span: Span) { + let mut applicability = Applicability::MachineApplicable; let snippet = match *vec_args { higher::VecArgs::Repeat(elem, len) => { if constant(cx, cx.tables, len).is_some() { - format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")) + format!( + "&[{}; {}]", + snippet_with_applicability(cx, elem.span, "elem", &mut applicability), + snippet_with_applicability(cx, len.span, "len", &mut applicability) + ) } else { return; } @@ -87,7 +93,7 @@ fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecA higher::VecArgs::Vec(args) => if let Some(last) = args.iter().last() { let span = args[0].span.to(last.span); - format!("&[{}]", snippet(cx, span, "..")) + format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability)) } else { "&[]".into() }, @@ -100,6 +106,7 @@ fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecA "useless use of `vec!`", "you can use a slice directly", snippet, + applicability, ); } diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index f84362fdbbc..0119560ccd8 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -8,13 +8,14 @@ // except according to those terms. -use crate::utils::{snippet, span_lint, span_lint_and_sugg}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::{declare_tool_lint, lint_array}; -use std::borrow::Cow; +use crate::rustc_errors::Applicability; use crate::syntax::ast::*; use crate::syntax::parse::{parser, token}; use crate::syntax::tokenstream::{ThinTokenStream, TokenStream}; +use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg}; +use std::borrow::Cow; /// **What it does:** This lint warns when you use `println!("")` to /// print a newline. @@ -199,6 +200,7 @@ impl EarlyLintPass for Pass { "using `println!(\"\")`", "replace it with", "println!()".to_string(), + Applicability::MachineApplicable, ); } } @@ -237,9 +239,14 @@ impl EarlyLintPass for Pass { let check_tts = check_tts(cx, &mac.node.tts, true); if let Some(fmtstr) = check_tts.0 { if fmtstr == "" { - let suggestion = check_tts - .1 - .map_or(Cow::Borrowed("v"), |expr| snippet(cx, expr.span, "v")); + let mut applicability = Applicability::MachineApplicable; + let suggestion = check_tts.1.map_or_else( + move || { + applicability = Applicability::HasPlaceholders; + Cow::Borrowed("v") + }, + move |expr| snippet_with_applicability(cx, expr.span, "v", &mut applicability), + ); span_lint_and_sugg( cx, @@ -248,6 +255,7 @@ impl EarlyLintPass for Pass { format!("using `writeln!({}, \"\")`", suggestion).as_str(), "replace it with", format!("writeln!({})", suggestion), + applicability, ); } } @@ -255,6 +263,20 @@ impl EarlyLintPass for Pass { } } +/// Checks the arguments of `print[ln]!` and `write[ln]!` calls. It will return a tuple of two +/// options. The first part of the tuple is `format_str` of the macros. The secund part of the tuple +/// is in the `write[ln]!` case the expression the `format_str` should be written to. +/// +/// Example: +/// +/// Calling this function on +/// ```rust,ignore +/// writeln!(buf, "string to write: {}", something) +/// ``` +/// will return +/// ```rust,ignore +/// (Some("string to write: {}"), Some(buf)) +/// ``` fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> (Option, Option) { use crate::fmt_macros::*; let tts = TokenStream::from(tts.clone()); diff --git a/tests/ui/else_if_without_else.stderr b/tests/ui/else_if_without_else.stderr index 9eddd4ab30d..7c8afcf3ce1 100644 --- a/tests/ui/else_if_without_else.stderr +++ b/tests/ui/else_if_without_else.stderr @@ -5,9 +5,10 @@ error: if expression with an `else if`, but without a final `else` | ____________^ 52 | | println!("else if"); 53 | | } - | |_____^ help: add an `else` block here + | |_____^ | = note: `-D clippy::else-if-without-else` implied by `-D warnings` + = help: add an `else` block here error: if expression with an `else if`, but without a final `else` --> $DIR/else_if_without_else.rs:59:12 @@ -16,7 +17,9 @@ error: if expression with an `else if`, but without a final `else` | ____________^ 60 | | println!("else if 2"); 61 | | } - | |_____^ help: add an `else` block here + | |_____^ + | + = help: add an `else` block here error: aborting due to 2 previous errors