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,
};
// function call
if let Some(args) = match_panic_call(cx, begin_panic_call);
if args.len() == 1;
if let Some(arg) = match_panic_call(cx, begin_panic_call);
// 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
// as is the second match arm
then {

View File

@ -1,5 +1,5 @@
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_lint::{EarlyContext, EarlyLintPass};
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 {
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
}

View File

@ -22,7 +22,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
use clippy_utils::paths;
use clippy_utils::source::{snippet, snippet_opt};
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! {
/// **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::Path(QPath::TypeRelative(ty, method)) = fun.kind;
if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind;
if let Some(ty_did) = ty_path.res.opt_def_id();
then {
if !TyS::same_type(self.target.ty(), self.maybe_typeck_results.unwrap().expr_ty(e)) {
return;
}
if match_path(ty_path, &paths::HASHMAP) {
if match_def_path(self.cx, ty_did, &paths::HASHMAP) {
if method.ident.name == sym::new {
self.suggestions
.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 {
self.suggestions
.insert(e.span, "HashSet::default()".to_string());

View File

@ -1,9 +1,9 @@
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 rustc_ast::ast::LitKind;
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_session::{declare_lint_pass, declare_tool_lint};
@ -87,7 +87,13 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
// Get the variable name
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 {
ExprKind::Lit(ref cond_lit) => {
@ -99,17 +105,30 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
};
}
},
ExprKind::Path(ref cond_num_path) => {
if INT_TYPES.iter().any(|int_type| match_qpath(cond_num_path, &[int_type, "MIN"])) {
print_lint_and_sugg(cx, &var_name, expr);
};
},
ExprKind::Call(func, _) => {
if let ExprKind::Path(ref cond_num_path) = func.kind {
if INT_TYPES.iter().any(|int_type| match_qpath(cond_num_path, &[int_type, "min_value"])) {
print_lint_and_sugg(cx, &var_name, expr);
ExprKind::Path(QPath::TypeRelative(_, name)) => {
if_chain! {
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);
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)
}
};
}
},
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::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_lint::{LateContext, LateLintPass};
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::Call(path, _) => {
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 {
Finite
}

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
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 rustc_errors::Applicability;
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 {
match expr.kind {
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,
}
}

View File

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

View File

@ -1,5 +1,5 @@
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 rustc_errors::Applicability;
use rustc_hir as hir;
@ -33,14 +33,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg:
}
}
if_chain! {
if let hir::ExprKind::Path(ref qpath) = filter_map_arg.kind;
if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY);
then {
apply_lint("called `filter_map(std::convert::identity)` on an `Iterator`");
}
if is_expr_path_def_path(cx, filter_map_arg, &paths::CONVERT_IDENTITY) {
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::{is_trait_method, match_qpath, paths};
use clippy_utils::{is_expr_path_def_path, is_trait_method, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
@ -16,8 +16,6 @@ pub(super) fn check<'tcx>(
flat_map_span: Span,
) {
if is_trait_method(cx, expr, sym::Iterator) {
let arg_node = &flat_map_arg.kind;
let apply_lint = |message: &str| {
span_lint_and_sugg(
cx,
@ -31,8 +29,8 @@ pub(super) fn check<'tcx>(
};
if_chain! {
if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node;
let body = cx.tcx.hir().body(*body_id);
if let hir::ExprKind::Closure(_, _, body_id, _, _) = flat_map_arg.kind;
let body = cx.tcx.hir().body(body_id);
if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.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 let hir::ExprKind::Path(ref qpath) = arg_node;
if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY);
then {
apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`");
}
if is_expr_path_def_path(cx, flat_map_arg, &paths::CONVERT_IDENTITY) {
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::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 rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::ExprKind;
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::Ty;
use rustc_span::sym;
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 let hir::ExprKind::Path(path) = func_kind;
if match_qpath(path, &["from_iter"]);
if is_expr_path_def_path(cx, func, &paths::FROM_ITERATOR_METHOD);
let ty = cx.typeck_results().expr_ty(expr);
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 implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]);
if implements_trait(cx, arg_ty, iter_id, &[]);
then {
// `expr` implements `FromIterator` trait
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::match_qpath;
use clippy_utils::is_qpath_def_path;
use clippy_utils::source::snippet_with_applicability;
use if_chain::if_chain;
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
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);
}
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);
}
}

View File

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

View File

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

View File

@ -20,8 +20,8 @@ use rustc_span::symbol::sym;
use crate::consts::{constant, Constant};
use clippy_utils::sugg::Sugg;
use clippy_utils::{
get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats,
last_path_segment, match_qpath, unsext, SpanlessEq,
expr_path_res, get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const,
iter_input_pats, last_path_segment, match_any_def_paths, paths, unsext, SpanlessEq,
};
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 => {
if let ExprKind::Path(ref path) = path.kind {
if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) {
(cx.typeck_results().expr_ty(&v[0]), snippet(cx, v[0].span, ".."))
} else {
return;
}
ExprKind::Call(path, [arg]) => {
if expr_path_res(cx, path)
.opt_def_id()
.and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM]))
.is_some()
{
(cx.typeck_results().expr_ty(arg), snippet(cx, arg.span, ".."))
} else {
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::source::snippet_opt;
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 rustc_errors::Applicability;
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 {
if_chain! {
if let ExprKind::Call(path, []) = expr.kind;
if let ExprKind::Path(ref qpath) = path.kind;
if let Some(fn_def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
then {
match_def_path(cx, fn_def_id, &paths::PTR_NULL) || match_def_path(cx, fn_def_id, &paths::PTR_NULL_MUT)
} else {
false
}
if let ExprKind::Call(pathexp, []) = expr.kind {
expr_path_res(cx, pathexp).opt_def_id().map_or(false, |id| {
match_any_def_paths(cx, id, &[&paths::PTR_NULL, &paths::PTR_NULL_MUT]).is_some()
})
} else {
false
}
}

View File

@ -3,10 +3,10 @@ use clippy_utils::is_lang_ctor;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
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 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_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -101,15 +101,14 @@ impl QuestionMark {
if Self::is_option(cx, subject);
if let PatKind::TupleStruct(path1, fields, None) = &arms[0].pat.kind;
if match_qpath(path1, &["Some"]);
if let PatKind::Binding(annot, _, bind, _) = &fields[0].kind;
if is_lang_ctor(cx, path1, OptionSome);
if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind;
let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
if let ExprKind::Block(block, None) = &arms[0].body.kind;
if block.stmts.is_empty();
if let Some(trailing_expr) = &block.expr;
if let ExprKind::Path(path) = &trailing_expr.kind;
if match_qpath(path, &[&bind.as_str()]);
if path_to_local_id(trailing_expr, bind_id);
if let PatKind::Wild = arms[1].pat.kind;
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::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 rustc_ast::ast::Attribute;
use rustc_errors::Applicability;
@ -84,9 +84,8 @@ impl<'tcx> LateLintPass<'tcx> for Return {
if local.ty.is_none();
if cx.tcx.hir().attrs(local.hir_id).is_empty();
if let Some(initexpr) = &local.init;
if let PatKind::Binding(.., ident, _) = local.pat.kind;
if let ExprKind::Path(qpath) = &retexpr.kind;
if match_qpath(qpath, &[&*ident.name.as_str()]);
if let PatKind::Binding(_, local_id, _, _) = local.pat.kind;
if path_to_local_id(retexpr, local_id);
if !last_statement_borrows(cx, initexpr);
if !in_external_macro(cx.sess(), initexpr.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::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 rustc_ast::ast::LitKind;
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_middle::hir::map::Map;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::Symbol;
use rustc_span::symbol::sym;
declare_clippy_lint! {
/// **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
/// `vec = Vec::with_capacity(0)`
struct VecAllocation<'tcx> {
/// Symbol of the local variable name
variable_name: Symbol,
/// HirId of the variable
local_id: HirId,
/// Reference to the expression which allocates the vector
allocation_expr: &'tcx Expr<'tcx>,
@ -72,16 +73,15 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
if_chain! {
if let ExprKind::Assign(left, right, _) = expr.kind;
// Extract variable name
if let ExprKind::Path(QPath::Resolved(_, path)) = left.kind;
if let Some(variable_name) = path.segments.get(0);
// Extract variable
if let Some(local_id) = path_to_local(left);
// 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 {
let vi = VecAllocation {
variable_name: variable_name.ident.name,
local_id,
allocation_expr: right,
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)`
if_chain! {
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(len_arg) = Self::is_vec_with_capacity(init);
if let Some(len_arg) = Self::is_vec_with_capacity(cx, init);
then {
let vi = VecAllocation {
variable_name: variable_name.name,
local_id,
allocation_expr: init,
len_expr: len_arg,
};
@ -115,19 +115,18 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
impl SlowVectorInit {
/// 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.
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 let ExprKind::Call(func, args) = expr.kind;
if let ExprKind::Path(ref path) = func.kind;
if match_qpath(path, &["Vec", "with_capacity"]);
if args.len() == 1;
if let ExprKind::Call(func, [arg]) = expr.kind;
if let ExprKind::Path(QPath::TypeRelative(ty, name)) = func.kind;
if name.ident.as_str() == "with_capacity";
if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::vec_type);
then {
return Some(&args[0]);
Some(arg)
} else {
None
}
}
None
}
/// 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<'_>) {
if_chain! {
if self.initialization_found;
if let ExprKind::MethodCall(path, _, args, _) = expr.kind;
if let ExprKind::Path(ref qpath_subj) = args[0].kind;
if match_qpath(qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]);
if let ExprKind::MethodCall(path, _, [self_arg, extend_arg], _) = expr.kind;
if path_to_local_id(self_arg, self.vec_alloc.local_id);
if path.ident.name == sym!(extend);
if let Some(extend_arg) = args.get(1);
if self.is_repeat_take(extend_arg);
then {
@ -225,11 +222,9 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) {
if_chain! {
if self.initialization_found;
if let ExprKind::MethodCall(path, _, args, _) = expr.kind;
if let ExprKind::Path(ref qpath_subj) = args[0].kind;
if match_qpath(qpath_subj, &[&*self.vec_alloc.variable_name.as_str()]);
if let ExprKind::MethodCall(path, _, [self_arg, len_arg, fill_arg], _) = expr.kind;
if path_to_local_id(self_arg, self.vec_alloc.local_id);
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
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)`
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
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)`
fn is_repeat_zero(expr: &Expr<'_>) -> bool {
fn is_repeat_zero(&self, expr: &Expr<'_>) -> bool {
if_chain! {
if let ExprKind::Call(fn_expr, repeat_args) = expr.kind;
if let ExprKind::Path(ref qpath_repeat) = fn_expr.kind;
if match_qpath(qpath_repeat, &["repeat"]);
if let Some(repeat_arg) = repeat_args.get(0);
if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind;
if is_expr_path_def_path(self.cx, fn_expr, &paths::ITER_REPEAT);
if let ExprKind::Lit(ref lit) = repeat_arg.kind;
if let LitKind::Int(0, _) = lit.node;
then {
return true
true
} else {
false
}
}
false
}
}

View File

@ -1,6 +1,6 @@
use crate::consts::{constant_context, Constant};
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 rustc_ast::LitKind;
use rustc_hir::{Expr, ExprKind};
@ -37,18 +37,15 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull {
}
if_chain! {
if let ExprKind::Call(func, args) = expr.kind;
if args.len() == 1;
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 {
if let ExprKind::Call(func, [arg]) = expr.kind;
if is_expr_path_def_path(cx, func, &paths::TRANSMUTE);
then {
// Catching transmute over constants that resolve to `null`.
let mut const_eval_context = constant_context(cx, cx.typeck_results());
if_chain! {
if let ExprKind::Path(ref _qpath) = args[0].kind;
let x = const_eval_context.expr(&args[0]);
if let ExprKind::Path(ref _qpath) = arg.kind;
let x = const_eval_context.expr(arg);
if let Some(Constant::RawPtr(0)) = x;
then {
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
@ -58,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull {
// Catching:
// `std::mem::transmute(0 as *const i32)`
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 LitKind::Int(0, _) = lit.node;
then {
@ -69,10 +66,8 @@ impl<'tcx> LateLintPass<'tcx> for TransmutingNull {
// Catching:
// `std::mem::transmute(std::ptr::null::<i32>())`
if_chain! {
if let ExprKind::Call(func1, []) = args[0].kind;
if let ExprKind::Path(ref path1) = func1.kind;
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);
if let ExprKind::Call(func1, []) = arg.kind;
if is_expr_path_def_path(cx, func1, &paths::PTR_NULL);
then {
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::source::snippet;
use clippy_utils::{match_path, paths};
use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{
@ -28,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
_ => None,
});
then {
if is_any_trait(inner) {
if is_any_trait(cx, inner) {
// Ignore `Box<Any>` types; see issue #1884 for details.
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.
fn is_any_trait(t: &hir::Ty<'_>) -> bool {
fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool {
if_chain! {
if let TyKind::TraitObject(traits, ..) = t.kind;
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
// 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 {
return true;
}

View File

@ -104,14 +104,12 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
if_chain! {
if !in_macro(ret_expr.span);
// Check if a function call.
if let ExprKind::Call(func, args) = ret_expr.kind;
// Get the Path of the function call.
if let ExprKind::Path(ref qpath) = func.kind;
if let ExprKind::Call(func, [arg]) = ret_expr.kind;
// 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 args.len() == 1;
// Make sure the function argument does not contain a return expression.
if !contains_return(&args[0]);
if !contains_return(arg);
then {
suggs.push(
(
@ -119,7 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
if inner_type.is_unit() {
"".to_string()
} 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::ty::match_type;
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 rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, ModKind, NodeId};
@ -578,8 +579,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
if_chain! {
if let ExprKind::Call(func, and_then_args) = expr.kind;
if let ExprKind::Path(ref path) = func.kind;
if match_qpath(path, &["span_lint_and_then"]);
if is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]);
if and_then_args.len() == 5;
if let ExprKind::Closure(_, _, body_id, _, _) = &and_then_args[4].kind;
let body = cx.tcx.hir().body(*body_id);
@ -761,8 +761,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
if_chain! {
// 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::Path(fn_qpath) = &fn_path.kind;
if match_qpath(fn_qpath, &["utils", "match_type"]);
if is_expr_path_def_path(cx, fn_path, &["clippy_utils", "ty", "match_type"]);
// Extract the path to the matched type
if let Some(segments) = path_to_matched_type(cx, ty_path);
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);
if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None });
then {
// TODO: check paths constants from external crates.
let cx_snippet = snippet(cx, context.span, "_");
let ty_snippet = snippet(cx, ty.span, "_");
@ -778,9 +778,9 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
cx,
MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
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",
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,
);
}

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
/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
/// `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)
}
/// 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.
pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
@ -1148,29 +1157,47 @@ pub fn match_function_call<'tcx>(
None
}
pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool {
// We have to convert `syms` to `&[Symbol]` here because rustc's `match_def_path`
// accepts only that. We should probably move to Symbols in Clippy as well.
let syms = syms.iter().map(|p| Symbol::intern(p)).collect::<Vec<Symbol>>();
cx.match_def_path(did, &syms)
/// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if
/// any.
pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option<usize> {
let search_path = cx.get_def_path(did);
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>]> {
match_function_call(cx, expr, &paths::BEGIN_PANIC)
.or_else(|| match_function_call(cx, expr, &paths::BEGIN_PANIC_FMT))
.or_else(|| match_function_call(cx, expr, &paths::PANIC_ANY))
.or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC))
.or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC_FMT))
.or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC_STR))
/// Checks if the given `DefId` matches the path.
pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool {
// We should probably move to Symbols in Clippy as well rather than interning every time.
let path = cx.get_def_path(did);
syms.iter().map(|x| Symbol::intern(x)).eq(path.iter().cloned())
}
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 {
match_def_path(cx, did, &paths::BEGIN_PANIC)
|| match_def_path(cx, did, &paths::BEGIN_PANIC_FMT)
|| match_def_path(cx, did, &paths::PANIC_ANY)
|| match_def_path(cx, did, &paths::PANICKING_PANIC)
|| match_def_path(cx, did, &paths::PANICKING_PANIC_FMT)
|| match_def_path(cx, did, &paths::PANICKING_PANIC_STR)
match_any_def_paths(
cx,
did,
&[
&paths::BEGIN_PANIC,
&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

View File

@ -4,7 +4,7 @@
//! Whenever possible, please consider diagnostic items over hardcoded paths.
//! 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 ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
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 FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
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 HASH: [&str; 3] = ["core", "hash", "Hash"];
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 IO_READ: [&str; 3] = ["std", "io", "Read"];
pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
pub const IPADDR_V4: [&str; 4] = ["std", "net", "IpAddr", "V4"];
pub const IPADDR_V6: [&str; 4] = ["std", "net", "IpAddr", "V6"];
pub const IPADDR_V4: [&str; 5] = ["std", "net", "ip", "IpAddr", "V4"];
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")]
pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
#[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_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "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_ERR: [&str; 4] = ["core", "result", "Result", "Err"];
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 STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
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 STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_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:
* [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]
* [The `if_chain` macro][if_chain]
* [`from_expansion`][from_expansion] and [`in_external_macro`][in_external_macro]

View File

@ -2,58 +2,18 @@
#![deny(clippy::internal)]
#![feature(rustc_private)]
extern crate clippy_utils;
extern crate rustc_ast;
extern crate rustc_errors;
extern crate rustc_lint;
extern crate rustc_session;
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_errors::{Applicability, DiagnosticBuilder};
use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
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! {
pub clippy::TEST_LINT,

View File

@ -2,58 +2,18 @@
#![deny(clippy::internal)]
#![feature(rustc_private)]
extern crate clippy_utils;
extern crate rustc_ast;
extern crate rustc_errors;
extern crate rustc_lint;
extern crate rustc_session;
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_errors::{Applicability, DiagnosticBuilder};
use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
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! {
pub clippy::TEST_LINT,

View File

@ -1,5 +1,5 @@
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 | | 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)]`
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 | | 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)`
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 | | 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)`
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 | | 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)`
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 | | db.note(note_msg);

View File

@ -1,29 +1,18 @@
#![deny(clippy::internal)]
#![feature(rustc_private)]
extern crate clippy_utils;
extern crate rustc_hir;
extern crate rustc_lint;
extern crate rustc_middle;
#[macro_use]
extern crate rustc_session;
use clippy_utils::{paths, ty::match_type};
use rustc_hir::Expr;
use rustc_lint::{LateContext, LateLintPass};
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! {
pub TEST_LINT,
Warn,
@ -38,12 +27,12 @@ impl<'tcx> LateLintPass<'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx 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, &["core", "result", "Result"]);
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
--> $DIR/match_type_on_diag_item.rs:41:17
error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
--> $DIR/match_type_on_diag_item.rs:31:17
|
LL | let _ = match_type(cx, ty, &paths::VEC);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::vec_type)`
LL | let _ = match_type(cx, ty, &OPTION);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::option_type)`
|
note: the lint level is defined here
--> $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)]`
error: usage of `utils::match_type()` on a type diagnostic item
--> $DIR/match_type_on_diag_item.rs:42: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
error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
--> $DIR/match_type_on_diag_item.rs:32:17
|
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
--> $DIR/match_type_on_diag_item.rs:46:17
error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
--> $DIR/match_type_on_diag_item.rs:35:17
|
LL | let _ = utils::match_type(cx, ty, rc_path);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::Rc)`
LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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)]
#![warn(clippy::all)]
#![allow(deprecated, invalid_value, clippy::uninit_assumed_init)]
#![warn(clippy::mem_replace_with_uninit)]
use std::mem;

View File

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