Remove all usages of match_path, match_qpath and match_path_ast except the author lint.

Add note to fix `MATCH_TYPE_ON_DIAG_ITEM`
Add false negative test for `uninit_assumed_init`
This commit is contained in:
Jason Newcomb 2021-04-07 16:19:25 -04:00
parent b1c675f3fc
commit f6c5d8d599
No known key found for this signature in database
GPG Key ID: DA59E8643A37ED06
34 changed files with 271 additions and 337 deletions

View File

@ -127,10 +127,9 @@ fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)
_ => &block.expr, _ => &block.expr,
}; };
// function call // function call
if let Some(args) = match_panic_call(cx, begin_panic_call); if let Some(arg) = match_panic_call(cx, begin_panic_call);
if args.len() == 1;
// bind the second argument of the `assert!` macro if it exists // bind the second argument of the `assert!` macro if it exists
if let panic_message = snippet_opt(cx, args[0].span); if let panic_message = snippet_opt(cx, arg.span);
// second argument of begin_panic is irrelevant // second argument of begin_panic is irrelevant
// as is the second match arm // as is the second match arm
then { then {

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{in_macro, match_path_ast}; use clippy_utils::in_macro;
use rustc_ast::ast::{AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind}; use rustc_ast::ast::{AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind};
use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_session::{declare_tool_lint, impl_lint_pass};
@ -126,7 +126,9 @@ impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_B
fn is_bool_ty(ty: &Ty) -> bool { fn is_bool_ty(ty: &Ty) -> bool {
if let TyKind::Path(None, path) = &ty.kind { if let TyKind::Path(None, path) = &ty.kind {
return match_path_ast(path, &["bool"]); if let [name] = path.segments.as_slice() {
return name.ident.name == sym::bool;
}
} }
false false
} }

View File

@ -22,7 +22,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
use clippy_utils::paths; use clippy_utils::paths;
use clippy_utils::source::{snippet, snippet_opt}; use clippy_utils::source::{snippet, snippet_opt};
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{differing_macro_contexts, match_path}; use clippy_utils::{differing_macro_contexts, match_def_path};
declare_clippy_lint! { declare_clippy_lint! {
/// **What it does:** Checks for public `impl` or `fn` missing generalization /// **What it does:** Checks for public `impl` or `fn` missing generalization
@ -333,12 +333,13 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't
if let ExprKind::Call(fun, args) = e.kind; if let ExprKind::Call(fun, args) = e.kind;
if let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind; if let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind;
if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind; if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind;
if let Some(ty_did) = ty_path.res.opt_def_id();
then { then {
if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) { if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) {
return; return;
} }
if match_path(ty_path, &paths::HASHMAP) { if match_def_path(self.cx, ty_did, &paths::HASHMAP) {
if method.ident.name == sym::new { if method.ident.name == sym::new {
self.suggestions self.suggestions
.insert(e.span, "HashMap::default()".to_string()); .insert(e.span, "HashMap::default()".to_string());
@ -351,7 +352,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't
), ),
); );
} }
} else if match_path(ty_path, &paths::HASHSET) { } else if match_def_path(self.cx, ty_did, &paths::HASHSET) {
if method.ident.name == sym::new { if method.ident.name == sym::new {
self.suggestions self.suggestions
.insert(e.span, "HashSet::default()".to_string()); .insert(e.span, "HashSet::default()".to_string());

View File

@ -1,9 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::{in_macro, match_qpath, SpanlessEq}; use clippy_utils::{in_macro, SpanlessEq};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, StmtKind}; use rustc_hir::{lang_items::LangItem, BinOpKind, Expr, ExprKind, QPath, StmtKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -87,7 +87,13 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
// Get the variable name // Get the variable name
let var_name = ares_path.segments[0].ident.name.as_str(); let var_name = ares_path.segments[0].ident.name.as_str();
const INT_TYPES: [&str; 5] = ["i8", "i16", "i32", "i64", "i128"]; const INT_TYPES: [LangItem; 5] = [
LangItem::I8,
LangItem::I16,
LangItem::I32,
LangItem::I64,
LangItem::Isize
];
match cond_num_val.kind { match cond_num_val.kind {
ExprKind::Lit(ref cond_lit) => { ExprKind::Lit(ref cond_lit) => {
@ -99,17 +105,30 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
}; };
} }
}, },
ExprKind::Path(ref cond_num_path) => { ExprKind::Path(QPath::TypeRelative(_, name)) => {
if INT_TYPES.iter().any(|int_type| match_qpath(cond_num_path, &[int_type, "MIN"])) { if_chain! {
print_lint_and_sugg(cx, &var_name, expr); if name.ident.as_str() == "MIN";
}; if let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id);
}, if let Some(impl_id) = cx.tcx.impl_of_method(const_id);
ExprKind::Call(func, _) => { let mut int_ids = INT_TYPES.iter().filter_map(|&ty| cx.tcx.lang_items().require(ty).ok());
if let ExprKind::Path(ref cond_num_path) = func.kind { if int_ids.any(|int_id| int_id == impl_id);
if INT_TYPES.iter().any(|int_type| match_qpath(cond_num_path, &[int_type, "min_value"])) { then {
print_lint_and_sugg(cx, &var_name, expr); print_lint_and_sugg(cx, &var_name, expr)
} }
}; }
},
ExprKind::Call(func, []) => {
if_chain! {
if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind;
if name.ident.as_str() == "min_value";
if let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(func_id);
let mut int_ids = INT_TYPES.iter().filter_map(|&ty| cx.tcx.lang_items().require(ty).ok());
if int_ids.any(|int_id| int_id == impl_id);
then {
print_lint_and_sugg(cx, &var_name, expr)
}
}
}, },
_ => (), _ => (),
} }

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::{implements_trait, match_type}; use clippy_utils::ty::{implements_trait, match_type};
use clippy_utils::{get_trait_def_id, higher, match_qpath, paths}; use clippy_utils::{get_trait_def_id, higher, is_qpath_def_path, paths};
use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_hir::{BorrowKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -163,7 +163,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e), ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e),
ExprKind::Call(path, _) => { ExprKind::Call(path, _) => {
if let ExprKind::Path(ref qpath) = path.kind { if let ExprKind::Path(ref qpath) = path.kind {
match_qpath(qpath, &paths::REPEAT).into() is_qpath_def_path(cx, qpath, path.hir_id, &paths::ITER_REPEAT).into()
} else { } else {
Finite Finite
} }

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_adjusted, is_trait_method, match_path, match_var, paths, remove_blocks}; use clippy_utils::{is_adjusted, is_qpath_def_path, is_trait_method, match_var, paths, remove_blocks};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind}; use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind};
@ -80,7 +80,7 @@ fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a
fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
match expr.kind { match expr.kind {
ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)), ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
ExprKind::Path(QPath::Resolved(_, path)) => match_path(path, &paths::STD_CONVERT_IDENTITY), ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY),
_ => false, _ => false,
} }
} }

View File

@ -1701,7 +1701,7 @@ mod redundant_pattern_match {
use super::REDUNDANT_PATTERN_MATCHING; use super::REDUNDANT_PATTERN_MATCHING;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::{is_lang_ctor, is_trait_method, match_qpath, paths}; use clippy_utils::{is_lang_ctor, is_qpath_def_path, is_trait_method, paths};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -1735,8 +1735,8 @@ mod redundant_pattern_match {
kind = &inner.kind; kind = &inner.kind;
} }
let good_method = match kind { let good_method = match kind {
PatKind::TupleStruct(ref path, patterns, _) if patterns.len() == 1 => { PatKind::TupleStruct(ref path, [sub_pat], _) => {
if let PatKind::Wild = patterns[0].kind { if let PatKind::Wild = sub_pat.kind {
if is_lang_ctor(cx, path, ResultOk) { if is_lang_ctor(cx, path, ResultOk) {
"is_ok()" "is_ok()"
} else if is_lang_ctor(cx, path, ResultErr) { } else if is_lang_ctor(cx, path, ResultErr) {
@ -1745,9 +1745,9 @@ mod redundant_pattern_match {
"is_some()" "is_some()"
} else if is_lang_ctor(cx, path, PollReady) { } else if is_lang_ctor(cx, path, PollReady) {
"is_ready()" "is_ready()"
} else if match_qpath(path, &paths::IPADDR_V4) { } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V4) {
"is_ipv4()" "is_ipv4()"
} else if match_qpath(path, &paths::IPADDR_V6) { } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V6) {
"is_ipv6()" "is_ipv6()"
} else { } else {
return; return;
@ -1821,6 +1821,7 @@ mod redundant_pattern_match {
) if patterns_left.len() == 1 && patterns_right.len() == 1 => { ) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) { if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
find_good_method_for_match( find_good_method_for_match(
cx,
arms, arms,
path_left, path_left,
path_right, path_right,
@ -1831,6 +1832,7 @@ mod redundant_pattern_match {
) )
.or_else(|| { .or_else(|| {
find_good_method_for_match( find_good_method_for_match(
cx,
arms, arms,
path_left, path_left,
path_right, path_right,
@ -1850,6 +1852,7 @@ mod redundant_pattern_match {
{ {
if let PatKind::Wild = patterns[0].kind { if let PatKind::Wild = patterns[0].kind {
find_good_method_for_match( find_good_method_for_match(
cx,
arms, arms,
path_left, path_left,
path_right, path_right,
@ -1860,6 +1863,7 @@ mod redundant_pattern_match {
) )
.or_else(|| { .or_else(|| {
find_good_method_for_match( find_good_method_for_match(
cx,
arms, arms,
path_left, path_left,
path_right, path_right,
@ -1900,7 +1904,9 @@ mod redundant_pattern_match {
} }
} }
#[allow(clippy::too_many_arguments)]
fn find_good_method_for_match<'a>( fn find_good_method_for_match<'a>(
cx: &LateContext<'_>,
arms: &[Arm<'_>], arms: &[Arm<'_>],
path_left: &QPath<'_>, path_left: &QPath<'_>,
path_right: &QPath<'_>, path_right: &QPath<'_>,
@ -1909,9 +1915,13 @@ mod redundant_pattern_match {
should_be_left: &'a str, should_be_left: &'a str,
should_be_right: &'a str, should_be_right: &'a str,
) -> Option<&'a str> { ) -> Option<&'a str> {
let body_node_pair = if match_qpath(path_left, expected_left) && match_qpath(path_right, expected_right) { let body_node_pair = if is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_left)
&& is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_right)
{
(&(*arms[0].body).kind, &(*arms[1].body).kind) (&(*arms[0].body).kind, &(*arms[1].body).kind)
} else if match_qpath(path_right, expected_left) && match_qpath(path_left, expected_right) { } else if is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_left)
&& is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_right)
{
(&(*arms[1].body).kind, &(*arms[0].body).kind) (&(*arms[1].body).kind, &(*arms[0].body).kind)
} else { } else {
return None; return None;

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::{is_trait_method, match_qpath, path_to_local_id, paths}; use clippy_utils::{is_expr_path_def_path, is_trait_method, path_to_local_id, paths};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
@ -33,14 +33,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg:
} }
} }
if_chain! { if is_expr_path_def_path(cx, filter_map_arg, &paths::CONVERT_IDENTITY) {
if let hir::ExprKind::Path(ref qpath) = filter_map_arg.kind; apply_lint("called `filter_map(std::convert::identity)` on an `Iterator`");
if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY);
then {
apply_lint("called `filter_map(std::convert::identity)` on an `Iterator`");
}
} }
} }
} }

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::{is_trait_method, match_qpath, paths}; use clippy_utils::{is_expr_path_def_path, is_trait_method, paths};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
@ -16,8 +16,6 @@ pub(super) fn check<'tcx>(
flat_map_span: Span, flat_map_span: Span,
) { ) {
if is_trait_method(cx, expr, sym::Iterator) { if is_trait_method(cx, expr, sym::Iterator) {
let arg_node = &flat_map_arg.kind;
let apply_lint = |message: &str| { let apply_lint = |message: &str| {
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
@ -31,8 +29,8 @@ pub(super) fn check<'tcx>(
}; };
if_chain! { if_chain! {
if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node; if let hir::ExprKind::Closure(_, _, body_id, _, _) = flat_map_arg.kind;
let body = cx.tcx.hir().body(*body_id); let body = cx.tcx.hir().body(body_id);
if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind; if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind;
if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = body.value.kind; if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = body.value.kind;
@ -45,14 +43,8 @@ pub(super) fn check<'tcx>(
} }
} }
if_chain! { if is_expr_path_def_path(cx, flat_map_arg, &paths::CONVERT_IDENTITY) {
if let hir::ExprKind::Path(ref qpath) = arg_node; apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`");
if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY);
then {
apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`");
}
} }
} }
} }

View File

@ -1,26 +1,23 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::implements_trait; use clippy_utils::ty::implements_trait;
use clippy_utils::{get_trait_def_id, match_qpath, paths, sugg}; use clippy_utils::{is_expr_path_def_path, paths, sugg};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::ExprKind;
use rustc_lint::{LateContext, LintContext}; use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;
use rustc_span::sym; use rustc_span::sym;
use super::FROM_ITER_INSTEAD_OF_COLLECT; use super::FROM_ITER_INSTEAD_OF_COLLECT;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func_kind: &ExprKind<'_>) { pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func: &hir::Expr<'_>) {
if_chain! { if_chain! {
if let hir::ExprKind::Path(path) = func_kind; if is_expr_path_def_path(cx, func, &paths::FROM_ITERATOR_METHOD);
if match_qpath(path, &["from_iter"]);
let ty = cx.typeck_results().expr_ty(expr); let ty = cx.typeck_results().expr_ty(expr);
let arg_ty = cx.typeck_results().expr_ty(&args[0]); let arg_ty = cx.typeck_results().expr_ty(&args[0]);
if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR);
if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator); if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]); if implements_trait(cx, arg_ty, iter_id, &[]);
then { then {
// `expr` implements `FromIterator` trait // `expr` implements `FromIterator` trait
let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par();

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::match_qpath; use clippy_utils::is_qpath_def_path;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast; use rustc_ast::ast;
@ -94,11 +94,11 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option<M
// `std::T::MAX` `std::T::MIN` constants // `std::T::MAX` `std::T::MIN` constants
if let hir::ExprKind::Path(path) = &expr.kind { if let hir::ExprKind::Path(path) = &expr.kind {
if match_qpath(path, &["core", &ty_str, "MAX"][..]) { if is_qpath_def_path(cx, path, expr.hir_id, &["core", &ty_str, "MAX"][..]) {
return Some(MinMax::Max); return Some(MinMax::Max);
} }
if match_qpath(path, &["core", &ty_str, "MIN"][..]) { if is_qpath_def_path(cx, path, expr.hir_id, &["core", &ty_str, "MIN"][..]) {
return Some(MinMax::Min); return Some(MinMax::Min);
} }
} }

View File

@ -1708,7 +1708,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
match expr.kind { match expr.kind {
hir::ExprKind::Call(func, args) => { hir::ExprKind::Call(func, args) => {
from_iter_instead_of_collect::check(cx, expr, args, &func.kind); from_iter_instead_of_collect::check(cx, expr, args, func);
}, },
hir::ExprKind::MethodCall(method_call, ref method_span, args, _) => { hir::ExprKind::MethodCall(method_call, ref method_span, args, _) => {
or_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args); or_fun_call::check(cx, expr, *method_span, &method_call.ident.as_str(), args);

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use clippy_utils::{match_def_path, match_qpath, paths}; use clippy_utils::{is_expr_path_def_path, match_def_path, paths};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::LateContext; use rustc_lint::LateContext;
@ -12,8 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
if_chain! { if_chain! {
if let hir::ExprKind::Call(callee, args) = recv.kind; if let hir::ExprKind::Call(callee, args) = recv.kind;
if args.is_empty(); if args.is_empty();
if let hir::ExprKind::Path(ref path) = callee.kind; if is_expr_path_def_path(cx, callee, &paths::MEM_MAYBEUNINIT_UNINIT);
if match_qpath(path, &paths::MEM_MAYBEUNINIT_UNINIT);
if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr)); if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr));
then { then {
span_lint( span_lint(

View File

@ -61,8 +61,6 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc
} }
return (true, false); return (true, false);
} }
// We don't know. It might do anything.
return (true, true);
} }
(true, true) (true, true)
}, },

View File

@ -20,8 +20,8 @@ use rustc_span::symbol::sym;
use crate::consts::{constant, Constant}; use crate::consts::{constant, Constant};
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::{ use clippy_utils::{
get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats, expr_path_res, get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const,
last_path_segment, match_qpath, unsext, SpanlessEq, iter_input_pats, last_path_segment, match_any_def_paths, paths, unsext, SpanlessEq,
}; };
declare_clippy_lint! { declare_clippy_lint! {
@ -564,13 +564,13 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left:
} }
) )
}, },
ExprKind::Call(path, v) if v.len() == 1 => { ExprKind::Call(path, [arg]) => {
if let ExprKind::Path(ref path) = path.kind { if expr_path_res(cx, path)
if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) { .opt_def_id()
(cx.typeck_results().expr_ty(&v[0]), snippet(cx, v[0].span, "..")) .and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM]))
} else { .is_some()
return; {
} (cx.typeck_results().expr_ty(arg), snippet(cx, arg.span, ".."))
} else { } else {
return; return;
} }

View File

@ -4,7 +4,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the
use clippy_utils::ptr::get_spans; use clippy_utils::ptr::get_spans;
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty}; use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty};
use clippy_utils::{is_allowed, match_def_path, paths}; use clippy_utils::{expr_path_res, is_allowed, match_any_def_paths, paths};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{ use rustc_hir::{
@ -417,14 +417,11 @@ fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability,
} }
fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
if_chain! { if let ExprKind::Call(pathexp, []) = expr.kind {
if let ExprKind::Call(path, []) = expr.kind; expr_path_res(cx, pathexp).opt_def_id().map_or(false, |id| {
if let ExprKind::Path(ref qpath) = path.kind; match_any_def_paths(cx, id, &[&paths::PTR_NULL, &paths::PTR_NULL_MUT]).is_some()
if let Some(fn_def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); })
then { } else {
match_def_path(cx, fn_def_id, &paths::PTR_NULL) || match_def_path(cx, fn_def_id, &paths::PTR_NULL_MUT) false
} else {
false
}
} }
} }

View File

@ -3,10 +3,10 @@ use clippy_utils::is_lang_ctor;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{eq_expr_value, match_qpath}; use clippy_utils::{eq_expr_value, path_to_local_id};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone; use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, MatchSource, PatKind, StmtKind}; use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, MatchSource, PatKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -101,15 +101,14 @@ impl QuestionMark {
if Self::is_option(cx, subject); if Self::is_option(cx, subject);
if let PatKind::TupleStruct(path1, fields, None) = &arms[0].pat.kind; if let PatKind::TupleStruct(path1, fields, None) = &arms[0].pat.kind;
if match_qpath(path1, &["Some"]); if is_lang_ctor(cx, path1, OptionSome);
if let PatKind::Binding(annot, _, bind, _) = &fields[0].kind; if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind;
let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut); let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
if let ExprKind::Block(block, None) = &arms[0].body.kind; if let ExprKind::Block(block, None) = &arms[0].body.kind;
if block.stmts.is_empty(); if block.stmts.is_empty();
if let Some(trailing_expr) = &block.expr; if let Some(trailing_expr) = &block.expr;
if let ExprKind::Path(path) = &trailing_expr.kind; if path_to_local_id(trailing_expr, bind_id);
if match_qpath(path, &[&bind.as_str()]);
if let PatKind::Wild = arms[1].pat.kind; if let PatKind::Wild = arms[1].pat.kind;
if Self::expression_returns_none(cx, arms[1].body); if Self::expression_returns_none(cx, arms[1].body);

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use clippy_utils::{fn_def_id, in_macro, match_qpath}; use clippy_utils::{fn_def_id, in_macro, path_to_local_id};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::Attribute; use rustc_ast::ast::Attribute;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -84,9 +84,8 @@ impl<'tcx> LateLintPass<'tcx> for Return {
if local.ty.is_none(); if local.ty.is_none();
if cx.tcx.hir().attrs(local.hir_id).is_empty(); if cx.tcx.hir().attrs(local.hir_id).is_empty();
if let Some(initexpr) = &local.init; if let Some(initexpr) = &local.init;
if let PatKind::Binding(.., ident, _) = local.pat.kind; if let PatKind::Binding(_, local_id, _, _) = local.pat.kind;
if let ExprKind::Path(qpath) = &retexpr.kind; if path_to_local_id(retexpr, local_id);
if match_qpath(qpath, &[&*ident.name.as_str()]);
if !last_statement_borrows(cx, initexpr); if !last_statement_borrows(cx, initexpr);
if !in_external_macro(cx.sess(), initexpr.span); if !in_external_macro(cx.sess(), initexpr.span);
if !in_external_macro(cx.sess(), retexpr.span); if !in_external_macro(cx.sess(), retexpr.span);

View File

@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::{get_enclosing_block, match_qpath, SpanlessEq}; use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{get_enclosing_block, is_expr_path_def_path, path_to_local, path_to_local_id, paths, SpanlessEq};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -9,7 +10,7 @@ use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, QPath,
use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_lint::{LateContext, LateLintPass, Lint};
use rustc_middle::hir::map::Map; use rustc_middle::hir::map::Map;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::Symbol; use rustc_span::symbol::sym;
declare_clippy_lint! { declare_clippy_lint! {
/// **What it does:** Checks slow zero-filled vector initialization /// **What it does:** Checks slow zero-filled vector initialization
@ -46,8 +47,8 @@ declare_lint_pass!(SlowVectorInit => [SLOW_VECTOR_INITIALIZATION]);
/// assigned to a variable. For example, `let mut vec = Vec::with_capacity(0)` or /// assigned to a variable. For example, `let mut vec = Vec::with_capacity(0)` or
/// `vec = Vec::with_capacity(0)` /// `vec = Vec::with_capacity(0)`
struct VecAllocation<'tcx> { struct VecAllocation<'tcx> {
/// Symbol of the local variable name /// HirId of the variable
variable_name: Symbol, local_id: HirId,
/// Reference to the expression which allocates the vector /// Reference to the expression which allocates the vector
allocation_expr: &'tcx Expr<'tcx>, allocation_expr: &'tcx Expr<'tcx>,
@ -72,16 +73,15 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
if_chain! { if_chain! {
if let ExprKind::Assign(left, right, _) = expr.kind; if let ExprKind::Assign(left, right, _) = expr.kind;
// Extract variable name // Extract variable
if let ExprKind::Path(QPath::Resolved(_, path)) = left.kind; if let Some(local_id) = path_to_local(left);
if let Some(variable_name) = path.segments.get(0);
// Extract len argument // Extract len argument
if let Some(len_arg) = Self::is_vec_with_capacity(right); if let Some(len_arg) = Self::is_vec_with_capacity(cx, right);
then { then {
let vi = VecAllocation { let vi = VecAllocation {
variable_name: variable_name.ident.name, local_id,
allocation_expr: right, allocation_expr: right,
len_expr: len_arg, len_expr: len_arg,
}; };
@ -95,13 +95,13 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
// Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)` // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)`
if_chain! { if_chain! {
if let StmtKind::Local(local) = stmt.kind; if let StmtKind::Local(local) = stmt.kind;
if let PatKind::Binding(BindingAnnotation::Mutable, .., variable_name, None) = local.pat.kind; if let PatKind::Binding(BindingAnnotation::Mutable, local_id, _, None) = local.pat.kind;
if let Some(init) = local.init; if let Some(init) = local.init;
if let Some(len_arg) = Self::is_vec_with_capacity(init); if let Some(len_arg) = Self::is_vec_with_capacity(cx, init);
then { then {
let vi = VecAllocation { let vi = VecAllocation {
variable_name: variable_name.name, local_id,
allocation_expr: init, allocation_expr: init,
len_expr: len_arg, len_expr: len_arg,
}; };
@ -115,19 +115,18 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
impl SlowVectorInit { impl SlowVectorInit {
/// Checks if the given expression is `Vec::with_capacity(..)`. It will return the expression /// Checks if the given expression is `Vec::with_capacity(..)`. It will return the expression
/// of the first argument of `with_capacity` call if it matches or `None` if it does not. /// of the first argument of `with_capacity` call if it matches or `None` if it does not.
fn is_vec_with_capacity<'tcx>(expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { fn is_vec_with_capacity<'tcx>(cx: &LateContext<'_>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
if_chain! { if_chain! {
if let ExprKind::Call(func, args) = expr.kind; if let ExprKind::Call(func, [arg]) = expr.kind;
if let ExprKind::Path(ref path) = func.kind; if let ExprKind::Path(QPath::TypeRelative(ty, name)) = func.kind;
if match_qpath(path, &["Vec", "with_capacity"]); if name.ident.as_str() == "with_capacity";
if args.len() == 1; if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::vec_type);
then { then {
return Some(&args[0]); Some(arg)
} else {
None
} }
} }
None
} }
/// Search initialization for the given vector /// Search initialization for the given vector
@ -208,11 +207,9 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) { fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) {
if_chain! { if_chain! {
if self.initialization_found; if self.initialization_found;
if let ExprKind::MethodCall(path, _, args, _) = expr.kind; if let ExprKind::MethodCall(path, _, [self_arg, extend_arg], _) = expr.kind;
if let ExprKind::Path(ref qpath_subj) = args[0].kind; if path_to_local_id(self_arg, self.vec_alloc.local_id);
if match_qpath(qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]);
if path.ident.name == sym!(extend); if path.ident.name == sym!(extend);
if let Some(extend_arg) = args.get(1);
if self.is_repeat_take(extend_arg); if self.is_repeat_take(extend_arg);
then { then {
@ -225,11 +222,9 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) { fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) {
if_chain! { if_chain! {
if self.initialization_found; if self.initialization_found;
if let ExprKind::MethodCall(path, _, args, _) = expr.kind; if let ExprKind::MethodCall(path, _, [self_arg, len_arg, fill_arg], _) = expr.kind;
if let ExprKind::Path(ref qpath_subj) = args[0].kind; if path_to_local_id(self_arg, self.vec_alloc.local_id);
if match_qpath(qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]);
if path.ident.name == sym!(resize); if path.ident.name == sym!(resize);
if let (Some(len_arg), Some(fill_arg)) = (args.get(1), args.get(2));
// Check that is filled with 0 // Check that is filled with 0
if let ExprKind::Lit(ref lit) = fill_arg.kind; if let ExprKind::Lit(ref lit) = fill_arg.kind;
@ -252,7 +247,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
// Check that take is applied to `repeat(0)` // Check that take is applied to `repeat(0)`
if let Some(repeat_expr) = take_args.get(0); if let Some(repeat_expr) = take_args.get(0);
if Self::is_repeat_zero(repeat_expr); if self.is_repeat_zero(repeat_expr);
// Check that len expression is equals to `with_capacity` expression // Check that len expression is equals to `with_capacity` expression
if let Some(len_arg) = take_args.get(1); if let Some(len_arg) = take_args.get(1);
@ -267,21 +262,19 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
} }
/// Returns `true` if given expression is `repeat(0)` /// Returns `true` if given expression is `repeat(0)`
fn is_repeat_zero(expr: &Expr<'_>) -> bool { fn is_repeat_zero(&self, expr: &Expr<'_>) -> bool {
if_chain! { if_chain! {
if let ExprKind::Call(fn_expr, repeat_args) = expr.kind; if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind;
if let ExprKind::Path(ref qpath_repeat) = fn_expr.kind; if is_expr_path_def_path(self.cx, fn_expr, &paths::ITER_REPEAT);
if match_qpath(qpath_repeat, &["repeat"]);
if let Some(repeat_arg) = repeat_args.get(0);
if let ExprKind::Lit(ref lit) = repeat_arg.kind; if let ExprKind::Lit(ref lit) = repeat_arg.kind;
if let LitKind::Int(0, _) = lit.node; if let LitKind::Int(0, _) = lit.node;
then { then {
return true true
} else {
false
} }
} }
false
} }
} }

View File

@ -1,6 +1,6 @@
use crate::consts::{constant_context, Constant}; use crate::consts::{constant_context, Constant};
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use clippy_utils::{match_def_path, paths}; use clippy_utils::{is_expr_path_def_path, paths};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::LitKind; use rustc_ast::LitKind;
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind};
@ -37,18 +37,15 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull {
} }
if_chain! { if_chain! {
if let ExprKind::Call(func, args) = expr.kind; if let ExprKind::Call(func, [arg]) = expr.kind;
if args.len() == 1; if is_expr_path_def_path(cx, func, &paths::TRANSMUTE);
if let ExprKind::Path(ref path) = func.kind;
if let Some(func_def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
if match_def_path(cx, func_def_id, &paths::TRANSMUTE);
then {
then {
// Catching transmute over constants that resolve to `null`. // Catching transmute over constants that resolve to `null`.
let mut const_eval_context = constant_context(cx, cx.typeck_results()); let mut const_eval_context = constant_context(cx, cx.typeck_results());
if_chain! { if_chain! {
if let ExprKind::Path(ref _qpath) = args[0].kind; if let ExprKind::Path(ref _qpath) = arg.kind;
let x = const_eval_context.expr(&args[0]); let x = const_eval_context.expr(arg);
if let Some(Constant::RawPtr(0)) = x; if let Some(Constant::RawPtr(0)) = x;
then { then {
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
@ -58,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull {
// Catching: // Catching:
// `std::mem::transmute(0 as *const i32)` // `std::mem::transmute(0 as *const i32)`
if_chain! { if_chain! {
if let ExprKind::Cast(inner_expr, _cast_ty) = args[0].kind; if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind;
if let ExprKind::Lit(ref lit) = inner_expr.kind; if let ExprKind::Lit(ref lit) = inner_expr.kind;
if let LitKind::Int(0, _) = lit.node; if let LitKind::Int(0, _) = lit.node;
then { then {
@ -69,10 +66,8 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull {
// Catching: // Catching:
// `std::mem::transmute(std::ptr::null::<i32>())` // `std::mem::transmute(std::ptr::null::<i32>())`
if_chain! { if_chain! {
if let ExprKind::Call(func1, []) = args[0].kind; if let ExprKind::Call(func1, []) = arg.kind;
if let ExprKind::Path(ref path1) = func1.kind; if is_expr_path_def_path(cx, func1, &paths::PTR_NULL);
if let Some(func1_def_id) = cx.qpath_res(path1, func1.hir_id).opt_def_id();
if match_def_path(cx, func1_def_id, &paths::PTR_NULL);
then { then {
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
} }

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::{match_path, paths}; use clippy_utils::{match_def_path, paths};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{ use rustc_hir::{
@ -28,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
_ => None, _ => None,
}); });
then { then {
if is_any_trait(inner) { if is_any_trait(cx, inner) {
// Ignore `Box<Any>` types; see issue #1884 for details. // Ignore `Box<Any>` types; see issue #1884 for details.
return false; return false;
} }
@ -84,13 +84,14 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
} }
// Returns true if given type is `Any` trait. // Returns true if given type is `Any` trait.
fn is_any_trait(t: &hir::Ty<'_>) -> bool { fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool {
if_chain! { if_chain! {
if let TyKind::TraitObject(traits, ..) = t.kind; if let TyKind::TraitObject(traits, ..) = t.kind;
if !traits.is_empty(); if !traits.is_empty();
if let Some(trait_did) = traits[0].trait_ref.trait_def_id();
// Only Send/Sync can be used as additional traits, so it is enough to // Only Send/Sync can be used as additional traits, so it is enough to
// check only the first trait. // check only the first trait.
if match_path(traits[0].trait_ref.path, &paths::ANY_TRAIT); if match_def_path(cx, trait_did, &paths::ANY_TRAIT);
then { then {
return true; return true;
} }

View File

@ -104,14 +104,12 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
if_chain! { if_chain! {
if !in_macro(ret_expr.span); if !in_macro(ret_expr.span);
// Check if a function call. // Check if a function call.
if let ExprKind::Call(func, args) = ret_expr.kind; if let ExprKind::Call(func, [arg]) = ret_expr.kind;
// Get the Path of the function call.
if let ExprKind::Path(ref qpath) = func.kind;
// Check if OPTION_SOME or RESULT_OK, depending on return type. // Check if OPTION_SOME or RESULT_OK, depending on return type.
if let ExprKind::Path(qpath) = &func.kind;
if is_lang_ctor(cx, qpath, lang_item); if is_lang_ctor(cx, qpath, lang_item);
if args.len() == 1;
// Make sure the function argument does not contain a return expression. // Make sure the function argument does not contain a return expression.
if !contains_return(&args[0]); if !contains_return(arg);
then { then {
suggs.push( suggs.push(
( (
@ -119,7 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
if inner_type.is_unit() { if inner_type.is_unit() {
"".to_string() "".to_string()
} else { } else {
snippet(cx, args[0].span.source_callsite(), "..").to_string() snippet(cx, arg.span.source_callsite(), "..").to_string()
} }
) )
); );

View File

@ -3,7 +3,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sug
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::ty::match_type; use clippy_utils::ty::match_type;
use clippy_utils::{ use clippy_utils::{
is_else_clause, is_expn_of, match_def_path, match_qpath, method_calls, path_to_res, paths, run_lints, SpanlessEq, is_else_clause, is_expn_of, is_expr_path_def_path, match_def_path, method_calls, path_to_res, paths, run_lints,
SpanlessEq,
}; };
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, ModKind, NodeId}; use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, ModKind, NodeId};
@ -578,8 +579,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
if_chain! { if_chain! {
if let ExprKind::Call(func, and_then_args) = expr.kind; if let ExprKind::Call(func, and_then_args) = expr.kind;
if let ExprKind::Path(ref path) = func.kind; if is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]);
if match_qpath(path, &["span_lint_and_then"]);
if and_then_args.len() == 5; if and_then_args.len() == 5;
if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind; if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind;
let body = cx.tcx.hir().body(*body_id); let body = cx.tcx.hir().body(*body_id);
@ -761,8 +761,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
if_chain! { if_chain! {
// Check if this is a call to utils::match_type() // Check if this is a call to utils::match_type()
if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind; if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind;
if let ExprKind::Path(fn_qpath) = &fn_path.kind; if is_expr_path_def_path(cx, fn_path, &["clippy_utils", "ty", "match_type"]);
if match_qpath(fn_qpath, &["utils", "match_type"]);
// Extract the path to the matched type // Extract the path to the matched type
if let Some(segments) = path_to_matched_type(cx, ty_path); if let Some(segments) = path_to_matched_type(cx, ty_path);
let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect(); let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
@ -771,6 +770,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
let diag_items = cx.tcx.diagnostic_items(ty_did.krate); let diag_items = cx.tcx.diagnostic_items(ty_did.krate);
if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None }); if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None });
then { then {
// TODO: check paths constants from external crates.
let cx_snippet = snippet(cx, context.span, "_"); let cx_snippet = snippet(cx, context.span, "_");
let ty_snippet = snippet(cx, ty.span, "_"); let ty_snippet = snippet(cx, ty.span, "_");
@ -778,9 +778,9 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
cx, cx,
MATCH_TYPE_ON_DIAGNOSTIC_ITEM, MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
expr.span, expr.span,
"usage of `utils::match_type()` on a type diagnostic item", "usage of `clippy_utils::ty::match_type()` on a type diagnostic item",
"try", "try",
format!("utils::is_type_diagnostic_item({}, {}, sym::{})", cx_snippet, ty_snippet, item_name), format!("clippy_utils::ty::is_type_diagnostic_item({}, {}, sym::{})", cx_snippet, ty_snippet, item_name),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} }

View File

@ -397,6 +397,29 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
} }
} }
/// If the expression is a path, resolve it. Otherwise, return `Res::Err`.
pub fn expr_path_res(cx: &LateContext<'_>, expr: &Expr<'_>) -> Res {
if let ExprKind::Path(p) = &expr.kind {
cx.qpath_res(p, expr.hir_id)
} else {
Res::Err
}
}
/// Resolves the path to a `DefId` and checks if it matches the given path.
pub fn is_qpath_def_path(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, segments: &[&str]) -> bool {
cx.qpath_res(path, hir_id)
.opt_def_id()
.map_or(false, |id| match_def_path(cx, id, segments))
}
/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path.
pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
expr_path_res(cx, expr)
.opt_def_id()
.map_or(false, |id| match_def_path(cx, id, segments))
}
/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from /// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
/// `QPath::Resolved.1.res.opt_def_id()`. /// `QPath::Resolved.1.res.opt_def_id()`.
@ -425,20 +448,6 @@ pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool {
.all(|(a, b)| a.ident.name.as_str() == *b) .all(|(a, b)| a.ident.name.as_str() == *b)
} }
/// Matches a `Path` against a slice of segment string literals, e.g.
///
/// # Examples
/// ```rust,ignore
/// match_path_ast(path, &["std", "rt", "begin_unwind"])
/// ```
pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
path.segments
.iter()
.rev()
.zip(segments.iter().rev())
.all(|(a, b)| a.ident.name.as_str() == *b)
}
/// If the expression is a path to a local, returns the canonical `HirId` of the local. /// If the expression is a path to a local, returns the canonical `HirId` of the local.
pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> { pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind { if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
@ -1148,29 +1157,47 @@ pub fn match_function_call<'tcx>(
None None
} }
pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool { /// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if
// We have to convert `syms` to `&[Symbol]` here because rustc's `match_def_path` /// any.
// accepts only that. We should probably move to Symbols in Clippy as well. pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option<usize> {
let syms = syms.iter().map(|p| Symbol::intern(p)).collect::<Vec<Symbol>>(); let search_path = cx.get_def_path(did);
cx.match_def_path(did, &syms) paths
.iter()
.position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().cloned()))
} }
pub fn match_panic_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx [Expr<'tcx>]> { /// Checks if the given `DefId` matches the path.
match_function_call(cx, expr, &paths::BEGIN_PANIC) pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool {
.or_else(|| match_function_call(cx, expr, &paths::BEGIN_PANIC_FMT)) // We should probably move to Symbols in Clippy as well rather than interning every time.
.or_else(|| match_function_call(cx, expr, &paths::PANIC_ANY)) let path = cx.get_def_path(did);
.or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC)) syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().cloned())
.or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC_FMT)) }
.or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC_STR))
pub fn match_panic_call(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
if let ExprKind::Call(func, [arg]) = expr.kind {
expr_path_res(cx, func)
.opt_def_id()
.map_or(false, |id| match_panic_def_id(cx, id))
.then(|| arg)
} else {
None
}
} }
pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool { pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool {
match_def_path(cx, did, &paths::BEGIN_PANIC) match_any_def_paths(
|| match_def_path(cx, did, &paths::BEGIN_PANIC_FMT) cx,
|| match_def_path(cx, did, &paths::PANIC_ANY) did,
|| match_def_path(cx, did, &paths::PANICKING_PANIC) &[
|| match_def_path(cx, did, &paths::PANICKING_PANIC_FMT) &paths::BEGIN_PANIC,
|| match_def_path(cx, did, &paths::PANICKING_PANIC_STR) &paths::BEGIN_PANIC_FMT,
&paths::PANIC_ANY,
&paths::PANICKING_PANIC,
&paths::PANICKING_PANIC_FMT,
&paths::PANICKING_PANIC_STR,
],
)
.is_some()
} }
/// Returns the list of condition expressions and the list of blocks in a /// Returns the list of condition expressions and the list of blocks in a

View File

@ -4,7 +4,7 @@
//! Whenever possible, please consider diagnostic items over hardcoded paths. //! Whenever possible, please consider diagnostic items over hardcoded paths.
//! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information. //! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.
pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"]; pub const ANY_TRAIT: [&str; 3] = ["core", "any", "Any"];
pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"]; pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"]; pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"]; pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
@ -42,6 +42,8 @@ pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments
pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"]; pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"]; pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"];
pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"];
pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"];
pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"]; pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
pub const HASH: [&str; 3] = ["core", "hash", "Hash"]; pub const HASH: [&str; 3] = ["core", "hash", "Hash"];
pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"];
@ -58,8 +60,9 @@ pub const INTO: [&str; 3] = ["core", "convert", "Into"];
pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"]; pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"];
pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"]; pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
pub const IPADDR_V4: [&str; 4] = ["std", "net", "IpAddr", "V4"]; pub const IPADDR_V4: [&str; 5] = ["std", "net", "ip", "IpAddr", "V4"];
pub const IPADDR_V6: [&str; 4] = ["std", "net", "IpAddr", "V6"]; pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"];
pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"];
#[cfg(feature = "internal-lints")] #[cfg(feature = "internal-lints")]
pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
#[cfg(feature = "internal-lints")] #[cfg(feature = "internal-lints")]
@ -126,7 +129,6 @@ pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"]; pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"]; pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"]; pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
pub const REPEAT: [&str; 3] = ["core", "iter", "repeat"];
pub const RESULT: [&str; 3] = ["core", "result", "Result"]; pub const RESULT: [&str; 3] = ["core", "result", "Result"];
pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"]; pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"];
pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"]; pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"];
@ -140,7 +142,7 @@ pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec
pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"]; pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"]; pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"];
pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"]; pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"];
pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"]; pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];

View File

@ -625,7 +625,7 @@ in the following steps:
Here are some pointers to things you are likely going to need for every lint: Here are some pointers to things you are likely going to need for every lint:
* [Clippy utils][utils] - Various helper functions. Maybe the function you need * [Clippy utils][utils] - Various helper functions. Maybe the function you need
is already in here (`implements_trait`, `match_path`, `snippet`, etc) is already in here (`implements_trait`, `match_def_path`, `snippet`, etc)
* [Clippy diagnostics][diagnostics] * [Clippy diagnostics][diagnostics]
* [The `if_chain` macro][if_chain] * [The `if_chain` macro][if_chain]
* [`from_expansion`][from_expansion] and [`in_external_macro`][in_external_macro] * [`from_expansion`][from_expansion] and [`in_external_macro`][in_external_macro]

View File

@ -2,58 +2,18 @@
#![deny(clippy::internal)] #![deny(clippy::internal)]
#![feature(rustc_private)] #![feature(rustc_private)]
extern crate clippy_utils;
extern crate rustc_ast; extern crate rustc_ast;
extern crate rustc_errors; extern crate rustc_errors;
extern crate rustc_lint; extern crate rustc_lint;
extern crate rustc_session; extern crate rustc_session;
extern crate rustc_span; extern crate rustc_span;
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
use rustc_ast::ast::Expr; use rustc_ast::ast::Expr;
use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext}; use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
#[allow(unused_variables)]
pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
where
F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
{
}
#[allow(unused_variables)]
fn span_lint_and_help<'a, T: LintContext>(
cx: &'a T,
lint: &'static Lint,
span: Span,
msg: &str,
option_span: Option<Span>,
help: &str,
) {
}
#[allow(unused_variables)]
fn span_lint_and_note<'a, T: LintContext>(
cx: &'a T,
lint: &'static Lint,
span: Span,
msg: &str,
note_span: Option<Span>,
note: &str,
) {
}
#[allow(unused_variables)]
fn span_lint_and_sugg<'a, T: LintContext>(
cx: &'a T,
lint: &'static Lint,
sp: Span,
msg: &str,
help: &str,
sugg: String,
applicability: Applicability,
) {
}
declare_tool_lint! { declare_tool_lint! {
pub clippy::TEST_LINT, pub clippy::TEST_LINT,

View File

@ -2,58 +2,18 @@
#![deny(clippy::internal)] #![deny(clippy::internal)]
#![feature(rustc_private)] #![feature(rustc_private)]
extern crate clippy_utils;
extern crate rustc_ast; extern crate rustc_ast;
extern crate rustc_errors; extern crate rustc_errors;
extern crate rustc_lint; extern crate rustc_lint;
extern crate rustc_session; extern crate rustc_session;
extern crate rustc_span; extern crate rustc_span;
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
use rustc_ast::ast::Expr; use rustc_ast::ast::Expr;
use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext}; use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
#[allow(unused_variables)]
pub fn span_lint_and_then<'a, T: LintContext, F>(cx: &'a T, lint: &'static Lint, sp: Span, msg: &str, f: F)
where
F: for<'b> FnOnce(&mut DiagnosticBuilder<'b>),
{
}
#[allow(unused_variables)]
fn span_lint_and_help<'a, T: LintContext>(
cx: &'a T,
lint: &'static Lint,
span: Span,
msg: &str,
option_span: Option<Span>,
help: &str,
) {
}
#[allow(unused_variables)]
fn span_lint_and_note<'a, T: LintContext>(
cx: &'a T,
lint: &'static Lint,
span: Span,
msg: &str,
note_span: Option<Span>,
note: &str,
) {
}
#[allow(unused_variables)]
fn span_lint_and_sugg<'a, T: LintContext>(
cx: &'a T,
lint: &'static Lint,
sp: Span,
msg: &str,
help: &str,
sugg: String,
applicability: Applicability,
) {
}
declare_tool_lint! { declare_tool_lint! {
pub clippy::TEST_LINT, pub clippy::TEST_LINT,

View File

@ -1,5 +1,5 @@
error: this call is collapsible error: this call is collapsible
--> $DIR/collapsible_span_lint_calls.rs:75:9 --> $DIR/collapsible_span_lint_calls.rs:35:9
| |
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.span_suggestion(expr.span, help_msg, sugg.to_string(), Applicability::MachineApplicable); LL | | db.span_suggestion(expr.span, help_msg, sugg.to_string(), Applicability::MachineApplicable);
@ -14,7 +14,7 @@ LL | #![deny(clippy::internal)]
= note: `#[deny(clippy::collapsible_span_lint_calls)]` implied by `#[deny(clippy::internal)]` = note: `#[deny(clippy::collapsible_span_lint_calls)]` implied by `#[deny(clippy::internal)]`
error: this call is collapsible error: this call is collapsible
--> $DIR/collapsible_span_lint_calls.rs:78:9 --> $DIR/collapsible_span_lint_calls.rs:38:9
| |
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.span_help(expr.span, help_msg); LL | | db.span_help(expr.span, help_msg);
@ -22,7 +22,7 @@ LL | | });
| |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg)` | |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg)`
error: this call is collapsible error: this call is collapsible
--> $DIR/collapsible_span_lint_calls.rs:81:9 --> $DIR/collapsible_span_lint_calls.rs:41:9
| |
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.help(help_msg); LL | | db.help(help_msg);
@ -30,7 +30,7 @@ LL | | });
| |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg)` | |__________^ help: collapse into: `span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg)`
error: this call is collspible error: this call is collspible
--> $DIR/collapsible_span_lint_calls.rs:84:9 --> $DIR/collapsible_span_lint_calls.rs:44:9
| |
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.span_note(expr.span, note_msg); LL | | db.span_note(expr.span, note_msg);
@ -38,7 +38,7 @@ LL | | });
| |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg)` | |__________^ help: collapse into: `span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg)`
error: this call is collspible error: this call is collspible
--> $DIR/collapsible_span_lint_calls.rs:87:9 --> $DIR/collapsible_span_lint_calls.rs:47:9
| |
LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| { LL | / span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |db| {
LL | | db.note(note_msg); LL | | db.note(note_msg);

View File

@ -1,29 +1,18 @@
#![deny(clippy::internal)] #![deny(clippy::internal)]
#![feature(rustc_private)] #![feature(rustc_private)]
extern crate clippy_utils;
extern crate rustc_hir; extern crate rustc_hir;
extern crate rustc_lint; extern crate rustc_lint;
extern crate rustc_middle; extern crate rustc_middle;
#[macro_use] #[macro_use]
extern crate rustc_session; extern crate rustc_session;
use clippy_utils::{paths, ty::match_type};
use rustc_hir::Expr; use rustc_hir::Expr;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;
mod paths {
pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
}
mod utils {
use super::*;
pub fn match_type(_cx: &LateContext<'_>, _ty: Ty<'_>, _path: &[&str]) -> bool {
false
}
}
use utils::match_type;
declare_lint! { declare_lint! {
pub TEST_LINT, pub TEST_LINT,
Warn, Warn,
@ -38,12 +27,12 @@ impl<'tcx> LateLintPass<'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr) {
let ty = cx.typeck_results().expr_ty(expr); let ty = cx.typeck_results().expr_ty(expr);
let _ = match_type(cx, ty, &paths::VEC); let _ = match_type(cx, ty, &paths::VEC); // FIXME: Doesn't lint external paths
let _ = match_type(cx, ty, &OPTION); let _ = match_type(cx, ty, &OPTION);
let _ = match_type(cx, ty, &["core", "result", "Result"]); let _ = match_type(cx, ty, &["core", "result", "Result"]);
let rc_path = &["alloc", "rc", "Rc"]; let rc_path = &["alloc", "rc", "Rc"];
let _ = utils::match_type(cx, ty, rc_path); let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
} }
} }

View File

@ -1,8 +1,8 @@
error: usage of `utils::match_type()` on a type diagnostic item error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
--> $DIR/match_type_on_diag_item.rs:41:17 --> $DIR/match_type_on_diag_item.rs:31:17
| |
LL | let _ = match_type(cx, ty, &paths::VEC); LL | let _ = match_type(cx, ty, &OPTION);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::vec_type)` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::option_type)`
| |
note: the lint level is defined here note: the lint level is defined here
--> $DIR/match_type_on_diag_item.rs:1:9 --> $DIR/match_type_on_diag_item.rs:1:9
@ -11,23 +11,17 @@ LL | #![deny(clippy::internal)]
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
= note: `#[deny(clippy::match_type_on_diagnostic_item)]` implied by `#[deny(clippy::internal)]` = note: `#[deny(clippy::match_type_on_diagnostic_item)]` implied by `#[deny(clippy::internal)]`
error: usage of `utils::match_type()` on a type diagnostic item error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
--> $DIR/match_type_on_diag_item.rs:42:17 --> $DIR/match_type_on_diag_item.rs:32:17
|
LL | let _ = match_type(cx, ty, &OPTION);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::option_type)`
error: usage of `utils::match_type()` on a type diagnostic item
--> $DIR/match_type_on_diag_item.rs:43:17
| |
LL | let _ = match_type(cx, ty, &["core", "result", "Result"]); LL | let _ = match_type(cx, ty, &["core", "result", "Result"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::result_type)` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::result_type)`
error: usage of `utils::match_type()` on a type diagnostic item error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
--> $DIR/match_type_on_diag_item.rs:46:17 --> $DIR/match_type_on_diag_item.rs:35:17
| |
LL | let _ = utils::match_type(cx, ty, rc_path); LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::Rc)` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Rc)`
error: aborting due to 4 previous errors error: aborting due to 3 previous errors

View File

@ -1,5 +1,5 @@
#![allow(deprecated, invalid_value)] #![allow(deprecated, invalid_value, clippy::uninit_assumed_init)]
#![warn(clippy::all)] #![warn(clippy::mem_replace_with_uninit)]
use std::mem; use std::mem;

View File

@ -1,6 +1,6 @@
#![feature(stmt_expr_attributes)] #![feature(stmt_expr_attributes)]
use std::mem::MaybeUninit; use std::mem::{self, MaybeUninit};
fn main() { fn main() {
let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
@ -19,4 +19,7 @@ fn main() {
// This is OK, because all constitutent types are uninit-compatible. // This is OK, because all constitutent types are uninit-compatible.
let _: (MaybeUninit<usize>, [MaybeUninit<bool>; 2]) = unsafe { MaybeUninit::uninit().assume_init() }; let _: (MaybeUninit<usize>, [MaybeUninit<bool>; 2]) = unsafe { MaybeUninit::uninit().assume_init() };
// Was a false negative.
let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() };
} }

View File

@ -12,5 +12,11 @@ error: this call for this type may be undefined behavior
LL | let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() }; LL | let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors error: this call for this type may be undefined behavior
--> $DIR/uninit.rs:24:29
|
LL | let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors