Skip to content

Commit

Permalink
Replace some iteration with get_[type_]diagnostic_name
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexendoo committed Aug 17, 2024
1 parent 9aa656d commit 6993752
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 75 deletions.
37 changes: 17 additions & 20 deletions clippy_lints/src/collection_is_never_read.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item};
use clippy_utils::visitors::{for_each_expr, Visitable};
use clippy_utils::{get_enclosing_block, path_to_local_id};
use core::ops::ControlFlow;
use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::symbol::sym;
use rustc_span::Symbol;

declare_clippy_lint! {
/// ### What it does
Expand Down Expand Up @@ -44,24 +43,11 @@ declare_clippy_lint! {
}
declare_lint_pass!(CollectionIsNeverRead => [COLLECTION_IS_NEVER_READ]);

// Add `String` here when it is added to diagnostic items
static COLLECTIONS: [Symbol; 9] = [
sym::BTreeMap,
sym::BTreeSet,
sym::BinaryHeap,
sym::HashMap,
sym::HashSet,
sym::LinkedList,
sym::Option,
sym::Vec,
sym::VecDeque,
];

impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
// Look for local variables whose type is a container. Search surrounding block for read access.
if let PatKind::Binding(_, local_id, _, _) = local.pat.kind
&& match_acceptable_type(cx, local, &COLLECTIONS)
&& match_acceptable_type(cx, local)
&& let Some(enclosing_block) = get_enclosing_block(cx, local.hir_id)
&& has_no_read_access(cx, local_id, enclosing_block)
{
Expand All @@ -70,11 +56,22 @@ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
}
}

fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[Symbol]) -> bool {
fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool {
let ty = cx.typeck_results().pat_ty(local.pat);
collections.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym))
// String type is a lang item but not a diagnostic item for now so we need a separate check
|| is_type_lang_item(cx, ty, LangItem::String)
matches!(
get_type_diagnostic_name(cx, ty),
Some(
sym::BTreeMap
| sym::BTreeSet
| sym::BinaryHeap
| sym::HashMap
| sym::HashSet
| sym::LinkedList
| sym::Option
| sym::Vec
| sym::VecDeque
)
) || is_type_lang_item(cx, ty, LangItem::String)
}

fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirId, block: T) -> bool {
Expand Down
8 changes: 2 additions & 6 deletions clippy_lints/src/functions/must_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty};
use rustc_span::{sym, Span, Symbol};
use rustc_span::{sym, Span};

use clippy_utils::attrs::is_proc_macro;
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
Expand Down Expand Up @@ -193,17 +193,13 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet)
}
}

static KNOWN_WRAPPER_TYS: &[Symbol] = &[sym::Rc, sym::Arc];

fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet) -> bool {
match *ty.kind() {
// primitive types are never mutable
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
ty::Adt(adt, args) => {
tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.param_env)
|| KNOWN_WRAPPER_TYS
.iter()
.any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did()))
|| matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::Rc | sym::Arc))
&& args.types().any(|ty| is_mutable_ty(cx, ty, tys))
},
ty::Tuple(args) => args.iter().any(|ty| is_mutable_ty(cx, ty, tys)),
Expand Down
33 changes: 15 additions & 18 deletions clippy_lints/src/infinite_iter.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::higher;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::ty::{get_type_diagnostic_name, implements_trait};
use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::symbol::sym;

declare_clippy_lint! {
/// ### What it does
Expand Down Expand Up @@ -210,18 +210,6 @@ const COMPLETING_METHODS: [(&str, usize); 12] = [
("product", 0),
];

/// the paths of types that are known to be infinitely allocating
const INFINITE_COLLECTORS: &[Symbol] = &[
sym::BinaryHeap,
sym::BTreeMap,
sym::BTreeSet,
sym::HashMap,
sym::HashSet,
sym::LinkedList,
sym::Vec,
sym::VecDeque,
];

fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
match expr.kind {
ExprKind::MethodCall(method, receiver, args, _) => {
Expand All @@ -248,10 +236,19 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
}
} else if method.ident.name == sym!(collect) {
let ty = cx.typeck_results().expr_ty(expr);
if INFINITE_COLLECTORS
.iter()
.any(|diag_item| is_type_diagnostic_item(cx, ty, *diag_item))
{
if matches!(
get_type_diagnostic_name(cx, ty),
Some(
sym::BinaryHeap
| sym::BTreeMap
| sym::BTreeSet
| sym::HashMap
| sym::HashSet
| sym::LinkedList
| sym::Vec
| sym::VecDeque,
)
) {
return is_infinite(cx, receiver);
}
}
Expand Down
34 changes: 15 additions & 19 deletions clippy_lints/src/manual_retain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item};
use clippy_utils::{match_def_path, paths, SpanlessEq};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::ExprKind::Assign;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{impl_lint_pass, RustcVersion};
use rustc_session::impl_lint_pass;
use rustc_span::symbol::sym;
use rustc_span::Span;

Expand All @@ -20,16 +20,6 @@ const ACCEPTABLE_METHODS: [&[&str]; 5] = [
&paths::SLICE_INTO,
&paths::VEC_DEQUE_ITER,
];
const ACCEPTABLE_TYPES: [(rustc_span::Symbol, Option<RustcVersion>); 7] = [
(sym::BinaryHeap, Some(msrvs::BINARY_HEAP_RETAIN)),
(sym::BTreeSet, Some(msrvs::BTREE_SET_RETAIN)),
(sym::BTreeMap, Some(msrvs::BTREE_MAP_RETAIN)),
(sym::HashSet, Some(msrvs::HASH_SET_RETAIN)),
(sym::HashMap, Some(msrvs::HASH_MAP_RETAIN)),
(sym::Vec, None),
(sym::VecDeque, None),
];
const MAP_TYPES: [rustc_span::Symbol; 2] = [sym::BTreeMap, sym::HashMap];

declare_clippy_lint! {
/// ### What it does
Expand Down Expand Up @@ -264,16 +254,22 @@ fn match_acceptable_def_path(cx: &LateContext<'_>, collect_def_id: DefId) -> boo
}

fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: &Msrv) -> bool {
let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs();
ACCEPTABLE_TYPES.iter().any(|(ty, acceptable_msrv)| {
is_type_diagnostic_item(cx, expr_ty, *ty)
&& acceptable_msrv.map_or(true, |acceptable_msrv| msrv.meets(acceptable_msrv))
})
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
let required = match get_type_diagnostic_name(cx, ty) {
Some(sym::BinaryHeap) => msrvs::BINARY_HEAP_RETAIN,
Some(sym::BTreeSet) => msrvs::BTREE_SET_RETAIN,
Some(sym::BTreeMap) => msrvs::BTREE_MAP_RETAIN,
Some(sym::HashSet) => msrvs::HASH_SET_RETAIN,
Some(sym::HashMap) => msrvs::HASH_MAP_RETAIN,
Some(sym::Vec | sym::VecDeque) => return true,
_ => return false,
};
msrv.meets(required)
}

fn match_map_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
let expr_ty = cx.typeck_results().expr_ty(expr).peel_refs();
MAP_TYPES.iter().any(|ty| is_type_diagnostic_item(cx, expr_ty, *ty))
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
matches!(get_type_diagnostic_name(cx, ty), Some(sym::BTreeMap | sym::HashMap))
}

fn make_span_lint_and_sugg(cx: &LateContext<'_>, span: Span, sugg: String) {
Expand Down
9 changes: 5 additions & 4 deletions clippy_lints/src/methods/needless_collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::NEEDLESS_COLLECT;
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection};
use clippy_utils::ty::{get_type_diagnostic_name, make_normalized_projection, make_projection};
use clippy_utils::{
can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local, path_to_local_id,
CaptureKind,
Expand Down Expand Up @@ -88,9 +88,10 @@ pub(super) fn check<'tcx>(
Node::LetStmt(l) => {
if let PatKind::Binding(BindingMode::NONE | BindingMode::MUT, id, _, None) = l.pat.kind
&& let ty = cx.typeck_results().expr_ty(collect_expr)
&& [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList]
.into_iter()
.any(|item| is_type_diagnostic_item(cx, ty, item))
&& matches!(
get_type_diagnostic_name(cx, ty),
Some(sym::Vec | sym::VecDeque | sym::BinaryHeap | sym::LinkedList)
)
&& let iter_ty = cx.typeck_results().expr_ty(iter_expr)
&& let Some(block) = get_enclosing_block(cx, l.hir_id)
&& let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty))
Expand Down
14 changes: 6 additions & 8 deletions clippy_lints/src/mut_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,12 @@ impl<'tcx> MutableKeyType<'tcx> {
// generics (because the compiler cannot ensure immutability for unknown types).
fn check_ty_(&mut self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
let ty = ty.peel_refs();
if let ty::Adt(def, args) = ty.kind() {
let is_keyed_type = [sym::HashMap, sym::BTreeMap, sym::HashSet, sym::BTreeSet]
.iter()
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did()));
if !is_keyed_type {
return;
}

if let ty::Adt(def, args) = ty.kind()
&& matches!(
cx.tcx.get_diagnostic_name(def.did()),
Some(sym::HashMap | sym::BTreeMap | sym::HashSet | sym::BTreeSet)
)
{
let subst_ty = args.type_at(0);
if self.interior_mut.is_interior_mut_ty(cx, subst_ty) {
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
Expand Down

0 comments on commit 6993752

Please sign in to comment.