Merge pull request #3459 from flip1995/sugg_appl

Add Applicability to suggestion lints: Take 2
This commit is contained in:
Oliver S̶c̶h̶n̶e̶i̶d̶e̶r Scherer 2018-11-27 18:29:33 +01:00 committed by GitHub
commit b2601beb35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 547 additions and 297 deletions

View File

@ -532,6 +532,7 @@ impl EarlyLintPass for CfgAttrPass {
"`cfg_attr` is deprecated for rustfmt and got replaced by tool_attributes", "`cfg_attr` is deprecated for rustfmt and got replaced by tool_attributes",
"use", "use",
format!("{}rustfmt::skip]", attr_style), format!("{}rustfmt::skip]", attr_style),
Applicability::MachineApplicable,
); );
} }
} }

View File

@ -10,12 +10,15 @@
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; 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::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::{Name, UintTy}; 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, use crate::utils::{
walk_ptrs_ty}; 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 /// **What it does:** Checks for naive byte counts
/// ///
@ -89,14 +92,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ByteCount {
} else { } else {
&filter_args[0] &filter_args[0]
}; };
span_lint_and_sugg(cx, let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
NAIVE_BYTECOUNT, NAIVE_BYTECOUNT,
expr.span, expr.span,
"You appear to be counting bytes the naive way", "You appear to be counting bytes the naive way",
"Consider using the bytecount crate", "Consider using the bytecount crate",
format!("bytecount::count({}, {})", format!("bytecount::count({}, {})",
snippet(cx, haystack.span, ".."), snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
snippet(cx, needle.span, ".."))); snippet_with_applicability(cx, needle.span, "..", &mut applicability)),
applicability,
);
} }
}; };
} }

View File

@ -27,7 +27,7 @@ use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain; use if_chain::if_chain;
use crate::syntax::ast; 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::utils::sugg::Sugg;
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
@ -128,12 +128,16 @@ fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, else_: &ast::Expr) {
then { then {
match else_.node { match else_.node {
ast::ExprKind::If(..) | ast::ExprKind::IfLet(..) => { ast::ExprKind::If(..) | ast::ExprKind::IfLet(..) => {
span_lint_and_sugg(cx, let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
COLLAPSIBLE_IF, COLLAPSIBLE_IF,
block.span, block.span,
"this `else { if .. }` block can be collapsed", "this `else { if .. }` block can be collapsed",
"try", "try",
snippet_block(cx, else_.span, "..").into_owned()); snippet_block_with_applicability(cx, else_.span, "..", &mut applicability).into_owned(),
applicability,
);
} }
_ => (), _ => (),
} }

View File

@ -10,9 +10,10 @@
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; 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::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}; 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, expr.span,
&format!("Calling {} is more clear than this expression", replacement), &format!("Calling {} is more clear than this expression", replacement),
"try", "try",
replacement); replacement,
Applicability::Unspecified, // First resolve the TODO above
);
} }
}, },
QPath::TypeRelative(..) => {}, QPath::TypeRelative(..) => {},

View File

@ -13,9 +13,10 @@
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::source_map::Span; 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. /// **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 { macro_rules! lint_double_comparison {
($op:tt) => {{ ($op:tt) => {{
let lhs_str = snippet(cx, llhs.span, ""); let mut applicability = Applicability::MachineApplicable;
let rhs_str = snippet(cx, lrhs.span, ""); 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); let sugg = format!("{} {} {}", lhs_str, stringify!($op), rhs_str);
span_lint_and_sugg(cx, DOUBLE_COMPARISONS, span, span_lint_and_sugg(
cx,
DOUBLE_COMPARISONS,
span,
"This binary expression can be simplified", "This binary expression can be simplified",
"try", sugg); "try",
sugg,
applicability,
);
}} }}
} }
match (op, lkind, rkind) { match (op, lkind, rkind) {

View File

@ -11,12 +11,13 @@
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; 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 crate::syntax::source_map::Spanned;
use if_chain::if_chain;
use crate::consts::{constant, Constant}; use crate::consts::{constant, Constant};
use crate::utils::paths; 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 /// **What it does:** Checks for calculation of subsecond microseconds or milliseconds
/// from other `Duration` methods. /// from other `Duration` methods.
@ -60,13 +61,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DurationSubsec {
("subsec_nanos", 1_000) => "subsec_micros", ("subsec_nanos", 1_000) => "subsec_micros",
_ => return, _ => return,
}; };
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
DURATION_SUBSEC, DURATION_SUBSEC,
expr.span, expr.span,
&format!("Calling `{}()` is more concise than this calculation", suggested_fn), &format!("Calling `{}()` is more concise than this calculation", suggested_fn),
"try", "try",
format!("{}.{}()", snippet(cx, args[0].span, "_"), suggested_fn), format!("{}.{}()", snippet_with_applicability(cx, args[0].span, "_", &mut applicability), suggested_fn),
applicability,
); );
} }
} }

View File

@ -14,7 +14,7 @@ use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_ex
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::*; 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, /// **What it does:** Checks for usage of if expressions with an `else if` branch,
/// but without a final `else` branch. /// but without a final `else` branch.
@ -66,13 +66,12 @@ impl EarlyLintPass for ElseIfWithoutElse {
while let ExprKind::If(_, _, Some(ref els)) = item.node { while let ExprKind::If(_, _, Some(ref els)) = item.node {
if let ExprKind::If(_, _, None) = els.node { if let ExprKind::If(_, _, None) = els.node {
span_lint_and_sugg( span_help_and_lint(
cx, cx,
ELSE_IF_WITHOUT_ELSE, ELSE_IF_WITHOUT_ELSE,
els.span, els.span,
"if expression with an `else if`, but without a final `else`", "if expression with an `else if`, but without a final `else`",
"add an `else` block here", "add an `else` block here",
String::new()
); );
} }

View File

@ -10,15 +10,16 @@
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; 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::TyKind;
use std::f32; use crate::rustc::{declare_tool_lint, lint_array};
use std::f64; use crate::rustc_errors::Applicability;
use std::fmt;
use crate::syntax::ast::*; use crate::syntax::ast::*;
use crate::syntax_pos::symbol::Symbol; use crate::syntax_pos::symbol::Symbol;
use crate::utils::span_lint_and_sugg; 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 /// **What it does:** Checks for float literals with a precision greater
/// than that supported by the underlying type /// than that supported by the underlying type
@ -68,6 +69,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExcessivePrecision {
"float has excessive precision", "float has excessive precision",
"consider changing the type or truncating it to", "consider changing the type or truncating it to",
sugg, sugg,
Applicability::MachineApplicable,
); );
} }
} }

View File

@ -8,10 +8,11 @@
// except according to those terms. // 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::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use if_chain::if_chain; use if_chain::if_chain;
/// **What it does:** Checks for matches being used to destructure a single-variant enum /// **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); if match_var(body, arg);
then { then {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
INFALLIBLE_DESTRUCTURING_MATCH, INFALLIBLE_DESTRUCTURING_MATCH,
@ -80,10 +82,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
"try this", "try this",
format!( format!(
"let {}({}) = {};", "let {}({}) = {};",
snippet(cx, variant_name.span, ".."), snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
snippet(cx, local.pat.span, ".."), snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
snippet(cx, target.span, ".."), snippet_with_applicability(cx, target.span, "..", &mut applicability),
), ),
applicability,
); );
} }
} }

View File

@ -11,12 +11,13 @@
use crate::rustc::hir::def_id::DefId; use crate::rustc::hir::def_id::DefId;
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty; use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_data_structures::fx::FxHashSet; use crate::rustc_data_structures::fx::FxHashSet;
use crate::rustc_errors::Applicability;
use crate::syntax::ast::{Lit, LitKind, Name}; use crate::syntax::ast::{Lit, LitKind, Name};
use crate::syntax::source_map::{Span, Spanned}; 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()` /// **What it does:** Checks for getting the length of something via `.len()`
/// just to compare to zero, and suggests using `.is_empty()` where applicable. /// 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 { if let Spanned {
node: LitKind::Int(lit, _), 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]) { if method_name == "len" && args.len() == 1 && has_is_empty(cx, &args[0]) {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
LEN_ZERO, LEN_ZERO,
span, span,
&format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }), &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
"using `is_empty` is clearer and more explicit", "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,
); );
} }
} }

View File

@ -12,6 +12,7 @@
use crate::rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass}; use crate::rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::*; use crate::syntax::ast::*;
use crate::syntax_pos; use crate::syntax_pos;
use crate::utils::{snippet_opt, span_lint_and_sugg}; use crate::utils::{snippet_opt, span_lint_and_sugg};
@ -300,6 +301,7 @@ impl WarningType {
"mistyped literal suffix", "mistyped literal suffix",
"did you mean to write", "did you mean to write",
grouping_hint.to_string(), grouping_hint.to_string(),
Applicability::MaybeIncorrect,
), ),
WarningType::UnreadableLiteral => span_lint_and_sugg( WarningType::UnreadableLiteral => span_lint_and_sugg(
cx, cx,
@ -308,6 +310,7 @@ impl WarningType {
"long literal lacking separators", "long literal lacking separators",
"consider", "consider",
grouping_hint.to_owned(), grouping_hint.to_owned(),
Applicability::MachineApplicable,
), ),
WarningType::LargeDigitGroups => span_lint_and_sugg( WarningType::LargeDigitGroups => span_lint_and_sugg(
cx, cx,
@ -316,6 +319,7 @@ impl WarningType {
"digit groups should be smaller", "digit groups should be smaller",
"consider", "consider",
grouping_hint.to_owned(), grouping_hint.to_owned(),
Applicability::MachineApplicable,
), ),
WarningType::InconsistentDigitGrouping => span_lint_and_sugg( WarningType::InconsistentDigitGrouping => span_lint_and_sugg(
cx, cx,
@ -324,6 +328,7 @@ impl WarningType {
"digits grouped inconsistently by underscores", "digits grouped inconsistently by underscores",
"consider", "consider",
grouping_hint.to_owned(), grouping_hint.to_owned(),
Applicability::MachineApplicable,
), ),
WarningType::DecimalRepresentation => span_lint_and_sugg( WarningType::DecimalRepresentation => span_lint_and_sugg(
cx, cx,
@ -332,6 +337,7 @@ impl WarningType {
"integer literal has a better hexadecimal representation", "integer literal has a better hexadecimal representation",
"consider", "consider",
grouping_hint.to_owned(), grouping_hint.to_owned(),
Applicability::MachineApplicable,
), ),
}; };
} }

View File

@ -35,10 +35,12 @@ use crate::utils::{in_macro, sugg, sext};
use crate::utils::usage::mutated_variables; use crate::utils::usage::mutated_variables;
use crate::consts::{constant, Constant}; 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::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 /// **What it does:** Checks for for-loops that manually copy items between
/// slices that could be optimized by having a memcpy. /// 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; // 1) it was ugly with big bodies;
// 2) it was not indented properly; // 2) it was not indented properly;
// 3) it wasnt very smart (see #675). // 3) it wasnt very smart (see #675).
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
WHILE_LET_LOOP, WHILE_LET_LOOP,
@ -509,9 +512,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
"try", "try",
format!( format!(
"while let {} = {} {{ .. }}", "while let {} = {} {{ .. }}",
snippet(cx, arms[0].pats[0].span, ".."), snippet_with_applicability(cx, arms[0].pats[0].span, "..", &mut applicability),
snippet(cx, matchexpr.span, "..") 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", "this loop could be written as a `for` loop",
"try", "try",
format!("for {} in {} {{ .. }}", loop_var, iterator), format!("for {} in {} {{ .. }}", loop_var, iterator),
Applicability::HasPlaceholders,
); );
} }
} }
@ -1004,7 +1009,7 @@ fn detect_manual_memcpy<'a, 'tcx>(
let big_sugg = manual_copies let big_sugg = manual_copies
.into_iter() .into_iter()
.map(|(dst_var, src_var)| { .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_offset = print_sum(&start_str, &dst_var.offset);
let dst_limit = print_limit(end, dst_var.offset, &dst_var.var_name); let dst_limit = print_limit(end, dst_var.offset, &dst_var.var_name);
let src_offset = print_sum(&start_str, &src_var.offset); 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", "it looks like you're manually copying between slices",
"try replacing the loop by", "try replacing the loop by",
big_sugg, 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) { 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" { let muta = if method_name == "iter_mut" {
"mut " "mut "
} else { } else {
@ -1316,6 +1323,7 @@ fn lint_iter_method(cx: &LateContext<'_, '_>, args: &[Expr], arg: &Expr, method_
iteration methods", iteration methods",
"to write this more concisely, try", "to write this more concisely, try",
format!("&{}{}", muta, object), 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), _ => lint_iter_method(cx, args, arg, method_name),
}; };
} else { } 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( span_lint_and_sugg(
cx, cx,
EXPLICIT_INTO_ITER_LOOP, EXPLICIT_INTO_ITER_LOOP,
@ -1354,6 +1363,7 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat, arg: &Expr, expr: &Ex
iteration methods`", iteration methods`",
"to write this more concisely, try", "to write this more concisely, try",
object.to_string(), object.to_string(),
applicability,
); );
} }
} else if method_name == "next" && match_trait_method(cx, arg, &paths::ITERATOR) { } else if method_name == "next" && match_trait_method(cx, arg, &paths::ITERATOR) {

View File

@ -11,15 +11,12 @@
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; 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::syntax::source_map::Span;
use crate::utils::paths; use crate::utils::paths;
use crate::utils::{ use crate::utils::{in_macro, match_trait_method, match_type, remove_blocks, snippet_with_applicability, span_lint_and_sugg};
in_macro, match_trait_method, match_type,
remove_blocks, snippet,
span_lint_and_sugg,
};
use if_chain::if_chain; use if_chain::if_chain;
use crate::syntax::ast::Ident;
#[derive(Clone)] #[derive(Clone)]
pub struct Pass; 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) { 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 let hir::ExprKind::Path(hir::QPath::Resolved(None, ref path)) = path.node {
if path.segments.len() == 1 && path.segments[0].ident == name { if path.segments.len() == 1 && path.segments[0].ident == name {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
MAP_CLONE, MAP_CLONE,
replace, replace,
"You are using an explicit closure for cloning elements", "You are using an explicit closure for cloning elements",
"Consider calling the dedicated `cloned` method", "Consider calling the dedicated `cloned` method",
format!("{}.cloned()", snippet(cx, root, "..")), format!("{}.cloned()", snippet_with_applicability(cx, root, "..", &mut applicability)),
applicability,
) )
} }
} }

View File

@ -19,7 +19,7 @@ use crate::syntax::ast::LitKind;
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::paths; use crate::utils::paths;
use crate::utils::{expr_block, in_macro, is_allowed, is_expn_of, match_qpath, match_type, 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}; span_note_and_lint, walk_ptrs_ty};
use crate::utils::sugg::Sugg; use crate::utils::sugg::Sugg;
use crate::consts::{constant, Constant}; 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, arms[0].pats[0].span, ".."),
snippet(cx, ex.span, ".."), snippet(cx, ex.span, ".."),
expr_block(cx, &arms[0].body, None, ".."), 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 { if let Some(rb) = arm_ref {
let suggestion = if rb == BindingAnnotation::Ref { "as_ref" } else { "as_mut" }; let suggestion = if rb == BindingAnnotation::Ref { "as_ref" } else { "as_mut" };
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
MATCH_AS_REF, MATCH_AS_REF,
expr.span, expr.span,
&format!("use {}() instead", suggestion), &format!("use {}() instead", suggestion),
"try this", "try this",
format!("{}.{}()", snippet(cx, ex.span, "_"), suggestion) format!("{}.{}()", snippet_with_applicability(cx, ex.span, "_", &mut applicability), suggestion),
applicability,
) )
} }
} }

View File

@ -11,7 +11,8 @@
use crate::rustc::hir::{Expr, ExprKind, MutMutable, QPath}; use crate::rustc::hir::{Expr, ExprKind, MutMutable, QPath};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; 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; use if_chain::if_chain;
/// **What it does:** Checks for `mem::replace()` on an `Option` with /// **What it does:** Checks for `mem::replace()` on an `Option` with
@ -79,13 +80,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemReplace {
_ => return, _ => return,
}; };
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_OPTION_WITH_NONE,
expr.span, expr.span,
"replacing an `Option` with `None`", "replacing an `Option` with `None`",
"consider `Option::take()` instead", "consider `Option::take()` instead",
format!("{}.take()", snippet(cx, replaced_path.span, "")) format!("{}.take()", snippet_with_applicability(cx, replaced_path.span, "", &mut applicability)),
applicability,
); );
} }
} }

View File

@ -22,8 +22,9 @@ use crate::utils::sugg;
use crate::utils::{ use crate::utils::{
get_arg_name, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, is_self, is_self_ty, 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, 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, match_var, method_calls, method_chain_args, remove_blocks, return_ty, same_tys, single_segment_path, snippet,
span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, 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 if_chain::if_chain;
use matches::matches; 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, &[]) { if implements_trait(cx, arg_ty, default_trait_id, &[]) {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
OR_FUN_CALL, OR_FUN_CALL,
span, span,
&format!("use of `{}` followed by a call to `{}`", name, path), &format!("use of `{}` followed by a call to `{}`", name, path),
"try this", "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; 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), &format!("use of `{}` followed by a function call", name),
"try this", "try this",
format!("{}_{}({})", name, suffix, sugg), format!("{}_{}({})", name, suffix, sugg),
Applicability::HasPlaceholders,
); );
} }
@ -1153,11 +1157,15 @@ fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span:
None 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::AddrOf(_, ref format_arg) = a.node {
if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.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 { 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()); let span_replace_word = method_span.with_hi(span.hi());
if let Some(format_args) = extract_format_args(arg) { if let Some(format_args) = extract_format_args(arg) {
let mut applicability = Applicability::MachineApplicable;
let args_len = format_args.len(); let args_len = format_args.len();
let args: Vec<String> = format_args let args: Vec<String> = format_args
.into_iter() .into_iter()
.take(args_len - 1) .take(args_len - 1)
.map(|a| generate_format_arg_snippet(cx, a)) .map(|a| generate_format_arg_snippet(cx, a, &mut applicability))
.collect(); .collect();
let sugg = args.join(", "); 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), &format!("use of `{}` followed by a function call", name),
"try this", "try this",
format!("unwrap_or_else({} panic!({}))", closure, sugg), format!("unwrap_or_else({} panic!({}))", closure, sugg),
applicability,
); );
return; 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( span_lint_and_sugg(
cx, 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), &format!("use of `{}` followed by a function call", name),
"try this", "try this",
format!("unwrap_or_else({} {{ let msg = {}; panic!(msg) }}))", closure, sugg), 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", "using '.clone()' on a ref-counted pointer",
"try this", "try this",
format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet(cx, arg.span, "_")), 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; return;
}; };
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
STRING_EXTEND_CHARS, STRING_EXTEND_CHARS,
@ -1380,10 +1394,11 @@ fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::E
"try this", "try this",
format!( format!(
"{}.push_str({}{})", "{}.push_str({}{})",
snippet(cx, args[0].span, "_"), snippet_with_applicability(cx, args[0].span, "_", &mut applicability),
ref_str, 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 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 fold_span = next_point.with_hi(fold_args[2].span.hi() + BytePos(1));
let mut applicability = Applicability::MachineApplicable;
let sugg = if replacement_has_args { let sugg = if replacement_has_args {
format!( format!(
".{replacement}(|{s}| {r})", ".{replacement}(|{s}| {r})",
replacement = replacement_method_name, replacement = replacement_method_name,
s = second_arg_ident, s = second_arg_ident,
r = snippet(cx, right_expr.span, "EXPR"), r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability),
) )
} else { } else {
format!( 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", "this `.fold` can be written more succinctly using another method",
"try", "try",
sugg, 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) { 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, // Note: we don't want to lint `get_mut().unwrap` for HashMap or BTreeMap,
// because they do not implement `IndexMut` // because they do not implement `IndexMut`
let mut applicability = Applicability::MachineApplicable;
let expr_ty = cx.tables.expr_ty(&get_args[0]); let expr_ty = cx.tables.expr_ty(&get_args[0]);
let get_args_str = if get_args.len() > 1 { 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 { } else {
return; // not linting on a .get().unwrap() chain or variant 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!( format!(
"{}{}[{}]", "{}{}[{}]",
borrow_str, borrow_str,
snippet(cx, get_args[0].span, "_"), snippet_with_applicability(cx, get_args[0].span, "_", &mut applicability),
get_args_str get_args_str
), ),
applicability,
); );
} }
@ -2004,22 +2023,26 @@ fn lint_chars_cmp(
if let Some(segment) = single_segment_path(qpath); if let Some(segment) = single_segment_path(qpath);
if segment.ident.name == "Some"; if segment.ident.name == "Some";
then { then {
let mut applicability = Applicability::MachineApplicable;
let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0])); let self_ty = walk_ptrs_ty(cx.tables.expr_ty_adjusted(&args[0][0]));
if self_ty.sty != ty::Str { if self_ty.sty != ty::Str {
return false; return false;
} }
span_lint_and_sugg(cx, span_lint_and_sugg(
cx,
lint, lint,
info.expr.span, info.expr.span,
&format!("you should use the `{}` method", suggest), &format!("you should use the `{}` method", suggest),
"like this", "like this",
format!("{}{}.{}({})", format!("{}{}.{}({})",
if info.eq { "" } else { "!" }, if info.eq { "" } else { "!" },
snippet(cx, args[0][0].span, "_"), snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability),
suggest, suggest,
snippet(cx, arg_char[0].span, "_"))); snippet_with_applicability(cx, arg_char[0].span, "_", &mut applicability)),
applicability,
);
return true; 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. /// Checks for the `CHARS_LAST_CMP` lint.
fn lint_chars_last_cmp<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, info: &BinaryExprInfo<'_>) -> bool { 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 true
} else { } 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 hir::ExprKind::Lit(ref lit) = info.other.node;
if let ast::LitKind::Char(c) = lit.node; if let ast::LitKind::Char(c) = lit.node;
then { then {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
lint, lint,
@ -2063,9 +2087,10 @@ fn lint_chars_cmp_with_unwrap<'a, 'tcx>(
"like this", "like this",
format!("{}{}.{}('{}')", format!("{}{}.{}('{}')",
if info.eq { "" } else { "!" }, if info.eq { "" } else { "!" },
snippet(cx, args[0][0].span, "_"), snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability),
suggest, suggest,
c) c),
applicability,
); );
return true; 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 let ast::LitKind::Str(r, _) = lit.node;
if r.as_str().len() == 1; if r.as_str().len() == 1;
then { 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]); let hint = format!("'{}'", &snip[1..snip.len() - 1]);
span_lint_and_sugg( span_lint_and_sugg(
cx, 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", "single-character string constant used as pattern",
"try using a char instead", "try using a char instead",
hint, 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_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty); let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
if base_rcv_ty == base_res_ty && rcv_depth >= res_depth { if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
USELESS_ASREF, USELESS_ASREF,
expr.span, expr.span,
&format!("this call to `{}` does nothing", call_name), &format!("this call to `{}` does nothing", call_name),
"try this", "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, kind,
), ),
"call directly", "call directly",
method_name.to_owned(), method_name.to_string(),
Applicability::MachineApplicable,
); );
} }
} }

View File

@ -12,13 +12,14 @@
//! //!
//! This lint is **warn** by default //! This lint is **warn** by default
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; 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::ast::LitKind;
use crate::syntax::source_map::Spanned; 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::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 { /// **What it does:** Checks for expressions of the form `if c { true } else {
/// false }` /// false }`
@ -73,7 +74,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBool {
use self::Expression::*; use self::Expression::*;
if let ExprKind::If(ref pred, ref then_block, Some(ref else_expr)) = e.node { if let ExprKind::If(ref pred, ref then_block, Some(ref else_expr)) = e.node {
let reduce = |ret, not| { let reduce = |ret, not| {
let snip = Sugg::hir(cx, pred, "<predicate>"); let mut applicability = Applicability::MachineApplicable;
let snip = Sugg::hir_with_applicability(cx, pred, "<predicate>", &mut applicability);
let snip = if not { !snip } else { snip }; let snip = if not { !snip } else { snip };
let hint = if ret { 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", "this if-then-else expression returns a bool literal",
"you can reduce it to", "you can reduce it to",
hint, hint,
applicability,
); );
}; };
if let ExprKind::Block(ref then_block, _) = then_block.node { 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 { 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)) { match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
(Bool(true), Other) => { (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( span_lint_and_sugg(
cx, cx,
BOOL_COMPARISON, BOOL_COMPARISON,
e.span, e.span,
"equality checks against true are unnecessary", "equality checks against true are unnecessary",
"try simplifying it as shown", "try simplifying it as shown",
hint, hint.to_string(),
applicability,
); );
}, },
(Other, Bool(true)) => { (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( span_lint_and_sugg(
cx, cx,
BOOL_COMPARISON, BOOL_COMPARISON,
e.span, e.span,
"equality checks against true are unnecessary", "equality checks against true are unnecessary",
"try simplifying it as shown", "try simplifying it as shown",
hint, hint.to_string(),
applicability,
); );
}, },
(Bool(false), Other) => { (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( span_lint_and_sugg(
cx, cx,
BOOL_COMPARISON, BOOL_COMPARISON,
@ -172,10 +178,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
"equality checks against false can be replaced by a negation", "equality checks against false can be replaced by a negation",
"try simplifying it as shown", "try simplifying it as shown",
(!hint).to_string(), (!hint).to_string(),
applicability,
); );
}, },
(Other, Bool(false)) => { (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( span_lint_and_sugg(
cx, cx,
BOOL_COMPARISON, BOOL_COMPARISON,
@ -183,6 +190,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
"equality checks against false can be replaced by a negation", "equality checks against false can be replaced by a negation",
"try simplifying it as shown", "try simplifying it as shown",
(!hint).to_string(), (!hint).to_string(),
applicability,
); );
}, },
_ => (), _ => (),

View File

@ -8,10 +8,11 @@
// except according to those terms. // 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::def::Def;
use crate::rustc::hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource}; 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 crate::utils::{has_drop, in_macro, snippet_opt, span_lint, span_lint_and_sugg};
use std::ops::Deref; use std::ops::Deref;
@ -131,6 +132,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
"statement can be reduced", "statement can be reduced",
"replace it with", "replace it with",
snippet, snippet,
Applicability::MachineApplicable,
); );
} }
} }

View File

@ -10,9 +10,10 @@
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::*; use crate::syntax::ast::*;
use crate::syntax::source_map::Spanned; 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 /// **What it does:** Checks for operations where precedence may be unclear
/// and suggests to add parentheses. Currently it catches the following: /// 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 { 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( span_lint_and_sugg(
cx, cx,
PRECEDENCE, PRECEDENCE,
@ -61,39 +62,41 @@ impl EarlyLintPass for Precedence {
"operator precedence can trip the unwary", "operator precedence can trip the unwary",
"consider parenthesizing your expression", "consider parenthesizing your expression",
sugg, sugg,
appl,
); );
}; };
if !is_bit_op(op) { if !is_bit_op(op) {
return; return;
} }
let mut applicability = Applicability::MachineApplicable;
match (is_arith_expr(left), is_arith_expr(right)) { match (is_arith_expr(left), is_arith_expr(right)) {
(true, true) => { (true, true) => {
let sugg = format!( let sugg = format!(
"({}) {} ({})", "({}) {} ({})",
snippet(cx, left.span, ".."), snippet_with_applicability(cx, left.span, "..", &mut applicability),
op.to_string(), 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) => { (true, false) => {
let sugg = format!( let sugg = format!(
"({}) {} {}", "({}) {} {}",
snippet(cx, left.span, ".."), snippet_with_applicability(cx, left.span, "..", &mut applicability),
op.to_string(), 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) => { (false, true) => {
let sugg = format!( let sugg = format!(
"{} {} ({})", "{} {} ({})",
snippet(cx, left.span, ".."), snippet_with_applicability(cx, left.span, "..", &mut applicability),
op.to_string(), 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) => (), (false, false) => (),
} }
@ -105,13 +108,15 @@ impl EarlyLintPass for Precedence {
if let ExprKind::Lit(ref lit) = slf.node { if let ExprKind::Lit(ref lit) = slf.node {
match lit.node { match lit.node {
LitKind::Int(..) | LitKind::Float(..) | LitKind::FloatUnsuffixed(..) => { LitKind::Int(..) | LitKind::Float(..) | LitKind::FloatUnsuffixed(..) => {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
PRECEDENCE, PRECEDENCE,
expr.span, expr.span,
"unary minus has lower precedence than method call", "unary minus has lower precedence than method call",
"consider adding parentheses to clarify your intent", "consider adding parentheses to clarify your intent",
format!("-({})", snippet(cx, rhs.span, "..")), format!("-({})", snippet_with_applicability(cx, rhs.span, "..", &mut applicability)),
applicability,
); );
}, },
_ => (), _ => (),

View File

@ -9,6 +9,7 @@
use crate::rustc::{declare_tool_lint, hir, lint, lint_array}; use crate::rustc::{declare_tool_lint, hir, lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::utils; use crate::utils;
use std::fmt; 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); 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) { 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 { } else {
utils::span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, &msg); utils::span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, &msg);
} }

View File

@ -10,6 +10,7 @@
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::*; use crate::syntax::ast::*;
use crate::utils::{span_lint_and_sugg}; 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 let ExprKind::Path(None, path) = &field.expr.node {
if path.segments.len() == 1 && path.segments[0].ident == field.ident { if path.segments.len() == 1 && path.segments[0].ident == field.ident {
span_lint_and_sugg ( span_lint_and_sugg(
cx, cx,
REDUNDANT_FIELD_NAMES, REDUNDANT_FIELD_NAMES,
field.span, field.span,
"redundant field names in struct initialization", "redundant field names in struct initialization",
"replace it with", "replace it with",
field.ident.to_string() field.ident.to_string(),
Applicability::MachineApplicable,
); );
} }
} }

View File

@ -8,11 +8,12 @@
// except according to those terms. // except according to those terms.
use crate::syntax::ast::{Expr, ExprKind, UnOp};
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; 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 if_chain::if_chain;
use crate::utils::{snippet, span_lint_and_sugg};
/// **What it does:** Checks for usage of `*&` and `*&mut` in expressions. /// **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::Unary(UnOp::Deref, ref deref_target) = e.node;
if let ExprKind::AddrOf(_, ref addrof_target) = without_parens(deref_target).node; if let ExprKind::AddrOf(_, ref addrof_target) = without_parens(deref_target).node;
then { then {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
DEREF_ADDROF, DEREF_ADDROF,
e.span, e.span,
"immediately dereferencing a reference", "immediately dereferencing a reference",
"try this", "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::Paren(ref parened) = object.node;
if let ExprKind::AddrOf(_, ref inner) = parened.node; if let ExprKind::AddrOf(_, ref inner) = parened.node;
then { then {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
REF_IN_DEREF, REF_IN_DEREF,
@ -108,9 +112,10 @@ impl EarlyLintPass for DerefPass {
"try this", "try this",
format!( format!(
"{}.{}", "{}.{}",
snippet(cx, inner.span, "_"), snippet_with_applicability(cx, inner.span, "_", &mut applicability),
snippet(cx, field_name.span, "_") snippet_with_applicability(cx, field_name.span, "_", &mut applicability)
) ),
applicability,
); );
} }
} }

View File

@ -8,12 +8,13 @@
// except according to those terms. // 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;
use crate::rustc::hir::def::Def; 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 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 /// **What it does:** Checks for usage of `ATOMIC_X_INIT`, `ONCE_INIT`, and
/// `uX/iX::MIN/MAX`. /// `uX/iX::MIN/MAX`.
@ -61,6 +62,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ReplaceConsts {
&format!("using `{}`", const_path.last().expect("empty path")), &format!("using `{}`", const_path.last().expect("empty path")),
"try this", "try this",
repl_snip.to_string(), repl_snip.to_string(),
Applicability::MachineApplicable,
); );
return; return;
} }

View File

@ -10,6 +10,7 @@
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::source_map::Spanned; use crate::syntax::source_map::Spanned;
use crate::utils::SpanlessEq; use crate::utils::SpanlessEq;
use crate::utils::{get_parent_expr, is_allowed, match_type, paths, span_lint, span_lint_and_sugg, walk_ptrs_ty}; 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 { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
use crate::syntax::ast::{LitKind, StrStyle}; 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 let ExprKind::MethodCall(ref path, _, ref args) = e.node {
if path.ident.name == "as_bytes" { if path.ident.name == "as_bytes" {
@ -177,6 +178,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes {
} else { } else {
format!("\"{}\"", lit_content.as_str()) format!("\"{}\"", lit_content.as_str())
}; };
let mut applicability = Applicability::MachineApplicable;
if callsite.starts_with("include_str!") { if callsite.starts_with("include_str!") {
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
@ -184,7 +186,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes {
e.span, e.span,
"calling `as_bytes()` on `include_str!(..)`", "calling `as_bytes()` on `include_str!(..)`",
"consider using `include_bytes!(..)` instead", "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 } else if callsite == expanded
&& lit_content.as_str().chars().all(|c| c.is_ascii()) && lit_content.as_str().chars().all(|c| c.is_ascii())
@ -196,7 +203,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for StringLitAsBytes {
e.span, e.span,
"calling `as_bytes()` on a string literal", "calling `as_bytes()` on a string literal",
"consider using a byte string literal instead", "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,
); );
} }
} }

View File

@ -10,21 +10,21 @@
use std::cmp; use std::cmp;
use matches::matches;
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit::FnKind; use crate::rustc::hir::intravisit::FnKind;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; 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::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::abi::LayoutOf;
use crate::rustc_target::spec::abi::Abi;
use crate::syntax::ast::NodeId; use crate::syntax::ast::NodeId;
use crate::syntax_pos::Span; 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 /// **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 /// the argument type is `Copy` and small enough to be more efficient to always
@ -141,7 +141,9 @@ impl<'a, 'tcx> TriviallyCopyPassByRef {
input.span, input.span,
"this argument is passed by reference, but would be more efficient if passed by value", "this argument is passed by reference, but would be more efficient if passed by value",
"consider passing by value instead", "consider passing by value instead",
value_type); value_type,
Applicability::Unspecified,
);
} }
} }
} }

View File

@ -10,28 +10,31 @@
#![allow(clippy::default_hash_types)] #![allow(clippy::default_hash_types)]
use crate::consts::{constant, Constant};
use crate::reexport::*; use crate::reexport::*;
use crate::rustc::hir; 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::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::hir::*;
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use if_chain::if_chain;
use crate::rustc::ty::{self, Ty, TyCtxt, TypeckTables};
use crate::rustc::ty::layout::LayoutOf; 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::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::cmp::Ordering;
use std::collections::BTreeMap; 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 /// Handles all the linting of funky types
pub struct TypePass; 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() { let ltopt = if lt.is_elided() {
String::new() String::new()
} else { } else {
format!("{} ", lt.name.ident().name.as_str()) format!("{} ", lt.name.ident().as_str())
}; };
let mutopt = if mut_ty.mutbl == Mutability::MutMutable { let mutopt = if mut_ty.mutbl == Mutability::MutMutable {
"mut " "mut "
} else { } else {
"" ""
}; };
span_lint_and_sugg(cx, let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
BORROWED_BOX, BORROWED_BOX,
ast_ty.span, ast_ty.span,
"you seem to be trying to use `&Box<T>`. Consider using just `&T`", "you seem to be trying to use `&Box<T>`. Consider using just `&T`",
"try", "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 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", "passing a unit value to a function",
"if you intended to pass a unit value, use a unit literal instead", "if you intended to pass a unit value, use a unit literal instead",
"()".to_string(), "()".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 } if in_constant(cx, expr.id) { return }
// The suggestion is to use a function call, so if the original expression // The suggestion is to use a function call, so if the original expression
// has parens on the outside, they are no longer needed. // has parens on the outside, they are no longer needed.
let mut applicability = Applicability::MachineApplicable;
let opt = snippet_opt(cx, op.span); let opt = snippet_opt(cx, op.span);
let sugg = if let Some(ref snip) = opt { let sugg = if let Some(ref snip) = opt {
if should_strip_parens(op, snip) { 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() snip.as_str()
} }
} else { } 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), &format!("casting {} to {} may become silently lossy if types change", cast_from, cast_to),
"try", "try",
format!("{}::from({})", cast_to, sugg), 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 { match cast_from.sty {
ty::FnDef(..) | ty::FnPtr(_) => { 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); let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
if to_nbits < cx.tcx.data_layout.pointer_size.bits() { 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, expr.span,
&format!("casting function pointer `{}` to `{}`, which truncates the value", from_snippet, cast_to), &format!("casting function pointer `{}` to `{}`, which truncates the value", from_snippet, cast_to),
"try", "try",
format!("{} as usize", from_snippet) format!("{} as usize", from_snippet),
applicability,
); );
} else if cast_to.sty != ty::Uint(UintTy::Usize) { } 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, expr.span,
&format!("casting function pointer `{}` to `{}`", from_snippet, cast_to), &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to),
"try", "try",
format!("{} as usize", from_snippet) format!("{} as usize", from_snippet),
applicability,
); );
} }
}, },

View File

@ -8,15 +8,16 @@
// except according to those terms. // 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::intravisit::{walk_path, walk_ty, NestedVisitorMap, Visitor};
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty; use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array}; 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::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 /// **What it does:** Checks for unnecessary repetition of structure name when a
/// replacement with `Self` is applicable. /// replacement with `Self` is applicable.
@ -70,6 +71,7 @@ fn span_use_self_lint(cx: &LateContext<'_, '_>, path: &Path) {
"unnecessary structure name repetition", "unnecessary structure name repetition",
"use the applicable keyword", "use the applicable keyword",
"Self".to_owned(), "Self".to_owned(),
Applicability::MachineApplicable,
); );
} }

View File

@ -18,6 +18,7 @@ use crate::rustc::hir::*;
use crate::rustc::hir::def::Def; use crate::rustc::hir::def::Def;
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet}; use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet};
use crate::syntax::ast::{Crate as AstCrate, Ident, ItemKind, Name}; use crate::syntax::ast::{Crate as AstCrate, Ident, ItemKind, Name};
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
@ -281,6 +282,7 @@ impl EarlyLintPass for DefaultHashTypes {
&msg, &msg,
"use", "use",
replace.to_string(), replace.to_string(),
Applicability::MaybeIncorrect, // FxHashMap, ... needs another import
); );
} }
} }

View File

@ -7,44 +7,48 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::reexport::*; use crate::reexport::*;
use matches::matches;
use if_chain::if_chain;
use crate::rustc::hir; 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::Def;
use crate::rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
use crate::rustc::hir::intravisit::{NestedVisitorMap, Visitor}; use crate::rustc::hir::intravisit::{NestedVisitorMap, Visitor};
use crate::rustc::hir::Node; use crate::rustc::hir::Node;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, Level, Lint, LintContext}; use crate::rustc::lint::{LateContext, Level, Lint, LintContext};
use crate::rustc::session::Session; use crate::rustc::session::Session;
use crate::rustc::traits; 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::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::borrow::Cow;
use std::env; use std::env;
use std::mem; use std::mem;
use std::str::FromStr;
use std::rc::Rc; use std::rc::Rc;
use crate::syntax::ast::{self, LitKind}; use std::str::FromStr;
use crate::syntax::attr;
use crate::syntax::source_map::{Span, DUMMY_SP};
use crate::syntax::errors::DiagnosticBuilder;
use crate::syntax::symbol::{keywords, Symbol};
pub mod camel_case; pub mod camel_case;
pub mod author;
pub mod comparisons; pub mod comparisons;
pub mod conf; pub mod conf;
pub mod constants; pub mod constants;
mod hir_utils; mod hir_utils;
pub mod paths;
pub mod sugg;
pub mod inspector; pub mod inspector;
pub mod internal_lints; pub mod internal_lints;
pub mod author; pub mod paths;
pub mod ptr; pub mod ptr;
pub mod sugg;
pub mod usage; pub mod usage;
pub use self::hir_utils::{SpanlessEq, SpanlessHash}; 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); tcx.push_item_path(&mut apb, def_id, false);
apb.names.len() == path.len() apb.names.len() == path.len() && apb.names.into_iter().zip(path.iter()).all(|(a, &b)| *a == *b)
&& 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. /// 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 false
} }
pub fn last_path_segment(path: &QPath) -> &PathSegment { pub fn last_path_segment(path: &QPath) -> &PathSegment {
match *path { match *path {
QPath::Resolved(_, ref path) => path.segments QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"),
.last()
.expect("A path must have at least one segment"),
QPath::TypeRelative(_, ref seg) => seg, 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::Resolved(_, ref path) => match_path(path, segments),
QPath::TypeRelative(ref ty, ref segment) => match ty.node { QPath::TypeRelative(ref ty, ref segment) => match ty.node {
TyKind::Path(ref inner_path) => { 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] && segment.ident.name == segments[segments.len() - 1]
}, },
_ => false, _ => false,
@ -199,9 +197,7 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
/// Get the definition associated to a path. /// Get the definition associated to a path.
pub fn path_to_def(cx: &LateContext<'_, '_>, path: &[&str]) -> Option<def::Def> { pub fn path_to_def(cx: &LateContext<'_, '_>, path: &[&str]) -> Option<def::Def> {
let crates = cx.tcx.crates(); let crates = cx.tcx.crates();
let krate = crates let krate = crates.iter().find(|&&krate| cx.tcx.crate_name(krate) == path[0]);
.iter()
.find(|&&krate| cx.tcx.crate_name(krate) == path[0]);
if let Some(krate) = krate { if let Some(krate) = krate {
let krate = DefId { let krate = DefId {
krate: *krate, krate: *krate,
@ -254,10 +250,17 @@ pub fn implements_trait<'a, 'tcx>(
ty_params: &[Kind<'tcx>], ty_params: &[Kind<'tcx>],
) -> bool { ) -> bool {
let ty = cx.tcx.erase_regions(&ty); let ty = cx.tcx.erase_regions(&ty);
let obligation = let obligation = cx.tcx.predicate_for_trait_def(
cx.param_env,
traits::ObligationCause::dummy(),
trait_id,
0,
ty,
ty_params,
);
cx.tcx cx.tcx
.predicate_for_trait_def(cx.param_env, traits::ObligationCause::dummy(), trait_id, 0, ty, ty_params); .infer_ctxt()
cx.tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold(&obligation)) .enter(|infcx| infcx.predicate_must_hold(&obligation))
} }
/// Check whether this type implements Drop. /// Check whether this type implements Drop.
@ -326,14 +329,14 @@ pub fn method_chain_args<'a>(expr: &'a Expr, methods: &[&str]) -> Option<Vec<&'a
Some(matched) Some(matched)
} }
/// Get the name of the item the expression is in, if available. /// Get the name of the item the expression is in, if available.
pub fn get_item_name(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<Name> { pub fn get_item_name(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<Name> {
let parent_id = cx.tcx.hir.get_parent(expr.id); let parent_id = cx.tcx.hir.get_parent(expr.id);
match cx.tcx.hir.find(parent_id) { match cx.tcx.hir.find(parent_id) {
Some(Node::Item(&Item { ref name, .. })) => Some(*name), Some(Node::Item(&Item { ref name, .. })) => Some(*name),
Some(Node::TraitItem(&TraitItem { ident, .. })) | Some(Node::TraitItem(&TraitItem { ident, .. })) | Some(Node::ImplItem(&ImplItem { ident, .. })) => {
Some(Node::ImplItem(&ImplItem { ident, .. })) => Some(ident.name), Some(ident.name)
},
_ => None, _ => None,
} }
} }
@ -366,15 +369,11 @@ impl<'tcx> Visitor<'tcx> for ContainsName {
/// check if an `Expr` contains a certain name /// check if an `Expr` contains a certain name
pub fn contains_name(name: Name, expr: &Expr) -> bool { pub fn contains_name(name: Name, expr: &Expr) -> bool {
let mut cn = ContainsName { let mut cn = ContainsName { name, result: false };
name,
result: false,
};
cn.visit_expr(expr); cn.visit_expr(expr);
cn.result cn.result
} }
/// Convert a span to a code snippet if available, otherwise use default. /// Convert a span to a code snippet if available, otherwise use default.
/// ///
/// # Example /// # 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) 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 /// Same as `snippet`, but should only be used when it's clear that the input span is
/// not a macro argument. /// 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> { 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) 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 /// 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 { 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(); 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(); let string = option.unwrap_or_default();
if in_macro(expr.span) { if in_macro(expr.span) {
Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default))) 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)) Cow::Owned(format!("{}{}", code, string))
} else if string.is_empty() { } else if string.is_empty() {
Cow::Owned(format!("{{ {} }}", code)) 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> { 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) .skip(ignore_first as usize)
.filter_map(|l| { .filter_map(|l| {
if l.is_empty() { if l.is_empty() {
None None
} else { } else {
// ignore empty lines // ignore empty lines
Some( Some(l.char_indices().find(|&(_, x)| x != ch).unwrap_or((l.len(), ch)).0)
l.char_indices()
.find(|&(_, x)| x != ch)
.unwrap_or((l.len(), ch))
.0,
)
} }
}) })
.min() .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> { pub fn get_enclosing_block<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, node: NodeId) -> Option<&'tcx Block> {
let map = &cx.tcx.hir; 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)); .and_then(|enclosing_id| map.find(enclosing_id));
if let Some(node) = enclosing_node { if let Some(node) = enclosing_node {
match 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::Item(&Item {
node: ItemKind::Fn(_, _, _, eid), node: ItemKind::Fn(_, _, _, eid),
.. ..
}) | Node::ImplItem(&ImplItem { })
| Node::ImplItem(&ImplItem {
node: ImplItemKind::Method(_, eid), node: ImplItemKind::Method(_, eid),
.. ..
}) => match cx.tcx.hir.body(eid).value.node { }) => 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. /// 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. /// 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 /// ```ignore
/// error: This `.fold` can be more succinctly expressed as `.any` /// 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, msg: &str,
help: &str, help: &str,
sugg: String, sugg: String,
applicability: Applicability,
) { ) {
span_lint_and_then(cx, lint, sp, msg, |db| { 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<Item = (Span, String)>, I: IntoIterator<Item = (Span, String)>,
{ {
let sugg = CodeSuggestion { let sugg = CodeSuggestion {
substitutions: vec![ substitutions: vec![Substitution {
Substitution { parts: sugg
parts: sugg.into_iter() .into_iter()
.map(|(span, snippet)| { .map(|(span, snippet)| SubstitutionPart { snippet, span })
SubstitutionPart {
snippet,
span,
}
})
.collect(), .collect(),
} }],
],
msg: help_msg, msg: help_msg,
show_code_when_inline: true, show_code_when_inline: true,
applicability: Applicability::Unspecified, applicability: Applicability::Unspecified,
@ -729,9 +759,7 @@ impl LimitStack {
Self { stack: vec![limit] } Self { stack: vec![limit] }
} }
pub fn limit(&self) -> u64 { pub fn limit(&self) -> u64 {
*self.stack *self.stack.last().expect("there should always be a value in the 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) { pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) {
let stack = &mut self.stack; 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<Item = &'a ast::Attribute> { pub fn get_attr<'a>(attrs: &'a [ast::Attribute], name: &'static str) -> impl Iterator<Item = &'a ast::Attribute> {
attrs.iter().filter(move |attr| attrs.iter().filter(move |attr| {
attr.path.segments.len() == 2 && attr.path.segments.len() == 2
attr.path.segments[0].ident.to_string() == "clippy" && && attr.path.segments[0].ident.to_string() == "clippy"
attr.path.segments[1].ident.to_string() == name) && attr.path.segments[1].ident.to_string() == name
})
} }
fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) { fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) {
@ -769,7 +798,8 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'
/// See also `is_direct_expn_of`. /// See also `is_direct_expn_of`.
pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
loop { loop {
let span_name_span = span.ctxt() let span_name_span = span
.ctxt()
.outer() .outer()
.expn_info() .expn_info()
.map(|ei| (ei.format.name(), ei.call_site)); .map(|ei| (ei.format.name(), ei.call_site));
@ -792,7 +822,8 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
/// `bar!` by /// `bar!` by
/// `is_direct_expn_of`. /// `is_direct_expn_of`.
pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> { pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
let span_name_span = span.ctxt() let span_name_span = span
.ctxt()
.outer() .outer()
.expn_info() .expn_info()
.map(|ei| (ei.format.name(), ei.call_site)); .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::Lit(..) | PatKind::Range(..) => true,
PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id), 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::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) { PatKind::Struct(ref qpath, ref fields, _) => {
if is_enum_variant(cx, qpath, pat.hir_id) {
true true
} else { } else {
are_refutable(cx, fields.iter().map(|field| &*field.node.pat)) 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) { PatKind::TupleStruct(ref qpath, ref pats, _) => {
if is_enum_variant(cx, qpath, pat.hir_id) {
true true
} else { } else {
are_refutable(cx, pats.iter().map(|pat| &**pat)) 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<DefId> { pub fn opt_def_id(def: Def) -> Option<DefId> {
match def { match def {
Def::Fn(id) | Def::Fn(id)
Def::Mod(id) | | Def::Mod(id)
Def::Static(id, _) | | Def::Static(id, _)
Def::Variant(id) | | Def::Variant(id)
Def::VariantCtor(id, ..) | | Def::VariantCtor(id, ..)
Def::Enum(id) | | Def::Enum(id)
Def::TyAlias(id) | | Def::TyAlias(id)
Def::AssociatedTy(id) | | Def::AssociatedTy(id)
Def::TyParam(id) | | Def::TyParam(id)
Def::ForeignTy(id) | | Def::ForeignTy(id)
Def::Struct(id) | | Def::Struct(id)
Def::StructCtor(id, ..) | | Def::StructCtor(id, ..)
Def::Union(id) | | Def::Union(id)
Def::Trait(id) | | Def::Trait(id)
Def::TraitAlias(id) | | Def::TraitAlias(id)
Def::Method(id) | | Def::Method(id)
Def::Const(id) | | Def::Const(id)
Def::AssociatedConst(id) | | Def::AssociatedConst(id)
Def::Macro(id, ..) | | Def::Macro(id, ..)
Def::Existential(id) | | Def::Existential(id)
Def::AssociatedExistential(id) | | Def::AssociatedExistential(id)
Def::SelfCtor(id) | Def::SelfCtor(id) => Some(id),
=> Some(id),
Def::Upvar(..) | Def::Local(_) | Def::Label(..) | Def::PrimTy(..) | Def::SelfTy(..) | Def::Upvar(..)
Def::ToolMod | Def::NonMacroAttr{..} | Def::Err => None, | 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<ast::Name> {
} }
pub fn int_bits(tcx: TyCtxt<'_, '_, '_>, ity: ast::IntTy) -> u64 { 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)] #[allow(clippy::cast_possible_wrap)]
@ -1038,7 +1076,9 @@ pub fn unsext(tcx: TyCtxt<'_, '_, '_>, u: i128, ity: ast::IntTy) -> u128 {
/// clip unused bytes /// clip unused bytes
pub fn clip(tcx: TyCtxt<'_, '_, '_>, u: u128, ity: ast::UintTy) -> u128 { 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; let amt = 128 - bits;
(u << amt) >> amt (u << amt) >> amt
} }

View File

@ -24,7 +24,7 @@ use crate::syntax::parse::token;
use crate::syntax::print::pprust::token_to_string; use crate::syntax::print::pprust::token_to_string;
use crate::syntax::util::parser::AssocOp; use crate::syntax::util::parser::AssocOp;
use crate::syntax::ast; 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::syntax_pos::{BytePos, Pos};
use crate::rustc_errors::Applicability; 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))) 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. /// Prepare a suggestion from an expression.
pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self { pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
use crate::syntax::ast::RangeLimits; use crate::syntax::ast::RangeLimits;

View File

@ -8,14 +8,15 @@
// except according to those terms. // except according to those terms.
use crate::consts::constant;
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; 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::ty::{self, Ty};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::{higher, is_copy, snippet, span_lint_and_sugg}; use crate::utils::{higher, is_copy, snippet_with_applicability, span_lint_and_sugg};
use crate::consts::constant; use if_chain::if_chain;
/// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would /// **What it does:** Checks for usage of `&vec![..]` when using `&[..]` would
/// be possible. /// 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) { 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 { let snippet = match *vec_args {
higher::VecArgs::Repeat(elem, len) => { higher::VecArgs::Repeat(elem, len) => {
if constant(cx, cx.tables, len).is_some() { 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 { } else {
return; 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() { higher::VecArgs::Vec(args) => if let Some(last) = args.iter().last() {
let span = args[0].span.to(last.span); let span = args[0].span.to(last.span);
format!("&[{}]", snippet(cx, span, "..")) format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
} else { } else {
"&[]".into() "&[]".into()
}, },
@ -100,6 +106,7 @@ fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecA
"useless use of `vec!`", "useless use of `vec!`",
"you can use a slice directly", "you can use a slice directly",
snippet, snippet,
applicability,
); );
} }

View File

@ -8,13 +8,14 @@
// except according to those terms. // 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::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use std::borrow::Cow; use crate::rustc_errors::Applicability;
use crate::syntax::ast::*; use crate::syntax::ast::*;
use crate::syntax::parse::{parser, token}; use crate::syntax::parse::{parser, token};
use crate::syntax::tokenstream::{ThinTokenStream, TokenStream}; 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 /// **What it does:** This lint warns when you use `println!("")` to
/// print a newline. /// print a newline.
@ -199,6 +200,7 @@ impl EarlyLintPass for Pass {
"using `println!(\"\")`", "using `println!(\"\")`",
"replace it with", "replace it with",
"println!()".to_string(), "println!()".to_string(),
Applicability::MachineApplicable,
); );
} }
} }
@ -237,9 +239,14 @@ impl EarlyLintPass for Pass {
let check_tts = check_tts(cx, &mac.node.tts, true); let check_tts = check_tts(cx, &mac.node.tts, true);
if let Some(fmtstr) = check_tts.0 { if let Some(fmtstr) = check_tts.0 {
if fmtstr == "" { if fmtstr == "" {
let suggestion = check_tts let mut applicability = Applicability::MachineApplicable;
.1 let suggestion = check_tts.1.map_or_else(
.map_or(Cow::Borrowed("v"), |expr| snippet(cx, expr.span, "v")); move || {
applicability = Applicability::HasPlaceholders;
Cow::Borrowed("v")
},
move |expr| snippet_with_applicability(cx, expr.span, "v", &mut applicability),
);
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
@ -248,6 +255,7 @@ impl EarlyLintPass for Pass {
format!("using `writeln!({}, \"\")`", suggestion).as_str(), format!("using `writeln!({}, \"\")`", suggestion).as_str(),
"replace it with", "replace it with",
format!("writeln!({})", suggestion), 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<String>, Option<Expr>) { fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> (Option<String>, Option<Expr>) {
use crate::fmt_macros::*; use crate::fmt_macros::*;
let tts = TokenStream::from(tts.clone()); let tts = TokenStream::from(tts.clone());

View File

@ -5,9 +5,10 @@ error: if expression with an `else if`, but without a final `else`
| ____________^ | ____________^
52 | | println!("else if"); 52 | | println!("else if");
53 | | } 53 | | }
| |_____^ help: add an `else` block here | |_____^
| |
= note: `-D clippy::else-if-without-else` implied by `-D warnings` = 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` error: if expression with an `else if`, but without a final `else`
--> $DIR/else_if_without_else.rs:59:12 --> $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"); 60 | | println!("else if 2");
61 | | } 61 | | }
| |_____^ help: add an `else` block here | |_____^
|
= help: add an `else` block here
error: aborting due to 2 previous errors error: aborting due to 2 previous errors