use std::collections::BTreeMap;
use if_chain::if_chain;
-use rustc_ast::{FloatTy, IntTy, LitFloatType, LitIntType, LitKind, UintTy};
+use rustc_ast::{LitFloatType, LitIntType, LitKind};
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{
BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericBounds, GenericParamKind, HirId,
- ImplItem, ImplItemKind, Item, ItemKind, Lifetime, Lit, Local, MatchSource, MutTy, Mutability, Node, QPath, Stmt,
- StmtKind, SyntheticTyParamKind, TraitFn, TraitItem, TraitItemKind, TyKind, UnOp,
+ ImplItem, ImplItemKind, Item, ItemKind, LangItem, Lifetime, Lit, Local, MatchSource, MutTy, Mutability, Node,
+ QPath, Stmt, StmtKind, SyntheticTyParamKind, TraitFn, TraitItem, TraitItemKind, TyKind, UnOp,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::TypeFoldable;
-use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TyS, TypeAndMut, TypeckResults};
+use rustc_middle::ty::{self, FloatTy, InferTy, IntTy, Ty, TyCtxt, TyS, TypeAndMut, TypeckResults, UintTy};
use rustc_semver::RustcVersion;
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
use rustc_span::hygiene::{ExpnKind, MacroKind};
use crate::utils::paths;
use crate::utils::sugg::Sugg;
use crate::utils::{
- clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_hir_ty_cfg_dependant,
- is_type_diagnostic_item, last_path_segment, match_def_path, match_path, meets_msrv, method_chain_args,
- multispan_sugg, numeric_literal::NumericLiteral, qpath_res, reindent_multiline, sext, snippet, snippet_opt,
- snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg,
- span_lint_and_then, unsext,
+ clip, comparisons, differing_macro_contexts, get_qpath_generic_tys, higher, in_constant, indent_of, int_bits,
+ is_hir_ty_cfg_dependant, is_ty_param_diagnostic_item, is_ty_param_lang_item, is_type_diagnostic_item,
+ last_path_segment, match_def_path, match_path, meets_msrv, method_chain_args, multispan_sugg,
+ numeric_literal::NumericLiteral, reindent_multiline, sext, snippet, snippet_opt, snippet_with_applicability,
+ snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext,
};
declare_clippy_lint! {
fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
// Skip trait implementations; see issue #605.
if let Some(hir::Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_item(id)) {
- if let ItemKind::Impl { of_trait: Some(_), .. } = item.kind {
+ if let ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind {
return;
}
}
}
}
-/// Checks if `qpath` has last segment with type parameter matching `path`
-fn match_type_parameter(cx: &LateContext<'_>, qpath: &QPath<'_>, path: &[&str]) -> Option<Span> {
- let last = last_path_segment(qpath);
- if_chain! {
- if let Some(ref params) = last.args;
- if !params.parenthesized;
- if let Some(ty) = params.args.iter().find_map(|arg| match arg {
- GenericArg::Type(ty) => Some(ty),
- _ => None,
- });
- if let TyKind::Path(ref qpath) = ty.kind;
- if let Some(did) = qpath_res(cx, qpath, ty.hir_id).opt_def_id();
- if match_def_path(cx, did, path);
- then {
- return Some(ty.span);
- }
- }
- None
-}
-
fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> {
- if match_type_parameter(cx, qpath, &paths::STRING).is_some() {
- return Some("str");
- }
- if match_type_parameter(cx, qpath, &paths::OS_STRING).is_some() {
- return Some("std::ffi::OsStr");
- }
- if match_type_parameter(cx, qpath, &paths::PATH_BUF).is_some() {
- return Some("std::path::Path");
+ if is_ty_param_diagnostic_item(cx, qpath, sym::string_type).is_some() {
+ Some("str")
+ } else if is_ty_param_diagnostic_item(cx, qpath, sym::OsString).is_some() {
+ Some("std::ffi::OsStr")
+ } else if is_ty_param_diagnostic_item(cx, qpath, sym::PathBuf).is_some() {
+ Some("std::path::Path")
+ } else {
+ None
}
- None
}
fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Span> {
match hir_ty.kind {
TyKind::Path(ref qpath) if !is_local => {
let hir_id = hir_ty.hir_id;
- let res = qpath_res(cx, qpath, hir_id);
+ let res = cx.qpath_res(qpath, hir_id);
if let Some(def_id) = res.opt_def_id() {
if Some(def_id) == cx.tcx.lang_items().owned_box() {
if let Some(span) = match_borrows_parameter(cx, qpath) {
);
return; // don't recurse into the type
}
- if match_type_parameter(cx, qpath, &paths::VEC).is_some() {
+ if is_ty_param_diagnostic_item(cx, qpath, sym::vec_type).is_some() {
span_lint_and_help(
cx,
BOX_VEC,
hir_ty.span,
"you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
None,
- "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation.",
+ "`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation",
);
return; // don't recurse into the type
}
} else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
- if let Some(span) = match_type_parameter(cx, qpath, &paths::RC) {
+ if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Rc) {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
hir_ty.span,
"usage of `Rc<Rc<T>>`",
"try",
- snippet_with_applicability(cx, span, "..", &mut applicability).to_string(),
+ snippet_with_applicability(cx, ty.span, "..", &mut applicability).to_string(),
applicability,
);
return; // don't recurse into the type
}
- if match_type_parameter(cx, qpath, &paths::BOX).is_some() {
- let box_ty = match &last_path_segment(qpath).args.unwrap().args[0] {
- GenericArg::Type(ty) => match &ty.kind {
- TyKind::Path(qpath) => qpath,
- _ => return,
- },
+ if let Some(ty) = is_ty_param_lang_item(cx, qpath, LangItem::OwnedBox) {
+ let qpath = match &ty.kind {
+ TyKind::Path(qpath) => qpath,
_ => return,
};
- let inner_span = match &last_path_segment(&box_ty).args.unwrap().args[0] {
- GenericArg::Type(ty) => ty.span,
- _ => return,
+ let inner_span = match get_qpath_generic_tys(qpath).next() {
+ Some(ty) => ty.span,
+ None => return,
};
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
);
return; // don't recurse into the type
}
- if match_type_parameter(cx, qpath, &paths::VEC).is_some() {
- let vec_ty = match &last_path_segment(qpath).args.unwrap().args[0] {
- GenericArg::Type(ty) => match &ty.kind {
- TyKind::Path(qpath) => qpath,
- _ => return,
- },
+ if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::vec_type) {
+ let qpath = match &ty.kind {
+ TyKind::Path(qpath) => qpath,
_ => return,
};
- let inner_span = match &last_path_segment(&vec_ty).args.unwrap().args[0] {
- GenericArg::Type(ty) => ty.span,
- _ => return,
+ let inner_span = match get_qpath_generic_tys(qpath).next() {
+ Some(ty) => ty.span,
+ None => return,
};
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
);
return; // don't recurse into the type
}
- if match_type_parameter(cx, qpath, &paths::VEC).is_some() {
- let vec_ty = match &last_path_segment(qpath).args.unwrap().args[0] {
- GenericArg::Type(ty) => match &ty.kind {
- TyKind::Path(qpath) => qpath,
- _ => return,
- },
+ if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::vec_type) {
+ let qpath = match &ty.kind {
+ TyKind::Path(qpath) => qpath,
_ => return,
};
- let inner_span = match &last_path_segment(&vec_ty).args.unwrap().args[0] {
- GenericArg::Type(ty) => ty.span,
- _ => return,
+ let inner_span = match get_qpath_generic_tys(qpath).next() {
+ Some(ty) => ty.span,
+ None => return,
};
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
});
// ty is now _ at this point
if let TyKind::Path(ref ty_qpath) = ty.kind;
- let res = qpath_res(cx, ty_qpath, ty.hir_id);
+ let res = cx.qpath_res(ty_qpath, ty.hir_id);
if let Some(def_id) = res.opt_def_id();
if Some(def_id) == cx.tcx.lang_items().owned_box();
// At this point, we know ty is Box<T>, now get T
cx,
VEC_BOX,
hir_ty.span,
- "`Vec<T>` is already on the heap, the boxing is unnecessary.",
+ "`Vec<T>` is already on the heap, the boxing is unnecessary",
"try",
format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")),
Applicability::MachineApplicable,
}
}
} else if cx.tcx.is_diagnostic_item(sym::option_type, def_id) {
- if match_type_parameter(cx, qpath, &paths::OPTION).is_some() {
+ if is_ty_param_diagnostic_item(cx, qpath, sym::option_type).is_some() {
span_lint(
cx,
OPTION_OPTION,
cx,
LINKEDLIST,
hir_ty.span,
- "I see you're using a LinkedList! Perhaps you meant some other data structure?",
+ "you seem to be using a `LinkedList`! Perhaps you meant some other data structure?",
None,
"a `VecDeque` might work",
);
match mut_ty.ty.kind {
TyKind::Path(ref qpath) => {
let hir_id = mut_ty.ty.hir_id;
- let def = qpath_res(cx, qpath, hir_id);
+ let def = cx.qpath_res(qpath, hir_id);
if_chain! {
if let Some(def_id) = def.opt_def_id();
if Some(def_id) == cx.tcx.lang_items().owned_box();
fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: HirId) -> Option<GenericBounds<'tcx>> {
if_chain! {
- if let Some(did) = qpath_res(cx, qpath, id).opt_def_id();
+ if let Some(did) = cx.qpath_res(qpath, id).opt_def_id();
if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did);
if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
if synthetic == Some(SyntheticTyParamKind::ImplTrait);
.iter()
.filter(|arg| {
if is_unit(cx.typeck_results().expr_ty(arg)) && !is_unit_literal(arg) {
- !matches!(&arg.kind, ExprKind::Match(.., MatchSource::TryDesugar))
+ !matches!(
+ &arg.kind,
+ ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..)
+ )
} else {
false
}
}
fn is_unary_neg(expr: &Expr<'_>) -> bool {
- matches!(expr.kind, ExprKind::Unary(UnOp::UnNeg, _))
+ matches!(expr.kind, ExprKind::Unary(UnOp::Neg, _))
}
fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
match expr.kind {
ExprKind::Lit(ref lit) => Some(lit),
- ExprKind::Unary(UnOp::UnNeg, e) => {
+ ExprKind::Unary(UnOp::Neg, e) => {
if let ExprKind::Lit(ref lit) = e.kind {
Some(lit)
} else {
}
}
- if !cx.access_levels.is_exported(item.hir_id) {
+ if !cx.access_levels.is_exported(item.hir_id()) {
return;
}
match item.kind {
- ItemKind::Impl {
- ref generics,
- self_ty: ref ty,
- ref items,
- ..
- } => {
+ ItemKind::Impl(ref impl_) => {
let mut vis = ImplicitHasherTypeVisitor::new(cx);
- vis.visit_ty(ty);
+ vis.visit_ty(impl_.self_ty);
for target in &vis.found {
if differing_macro_contexts(item.span, target.span()) {
return;
}
- let generics_suggestion_span = generics.span.substitute_dummy({
+ let generics_suggestion_span = impl_.generics.span.substitute_dummy({
let pos = snippet_opt(cx, item.span.until(target.span()))
.and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)));
if let Some(pos) = pos {
});
let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);
- for item in items.iter().map(|item| cx.tcx.hir().impl_item(item.id)) {
+ for item in impl_.items.iter().map(|item| cx.tcx.hir().impl_item(item.id)) {
ctr_vis.visit_impl_item(item);
}
target.type_name()
),
move |diag| {
- suggestion(cx, diag, generics.span, generics_suggestion_span, target, ctr_vis);
+ suggestion(cx, diag, impl_.generics.span, generics_suggestion_span, target, ctr_vis);
},
);
}
impl<'tcx> LateLintPass<'tcx> for RefToMut {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
- if let ExprKind::Unary(UnOp::UnDeref, e) = &expr.kind;
+ if let ExprKind::Unary(UnOp::Deref, e) = &expr.kind;
if let ExprKind::Cast(e, t) = &e.kind;
if let TyKind::Ptr(MutTy { mutbl: Mutability::Mut, .. }) = t.kind;
if let ExprKind::Cast(e, t) = &e.kind;