needless_pass_by_value: reference the innermost Option content

If types such as `Option<Option<String>>` are not used by value, then
`Option<Option<&String>>` will be suggested, instead of
`Option<&Option<String>>`.
This commit is contained in:
Samuel Tardieu 2025-03-11 20:59:03 +01:00
parent 8f280ff813
commit 35e6057e71
4 changed files with 83 additions and 17 deletions

View file

@ -107,10 +107,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
use rustc_hir::{
self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext,
Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind,
ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat,
PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitFn, TraitItem, TraitItemKind,
TraitItemRef, TraitRef, TyKind, UnOp, def,
Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItem,
ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode,
Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitFn, TraitItem,
TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, def,
};
use rustc_lexer::{TokenKind, tokenize};
use rustc_lint::{LateContext, Level, Lint, LintContext};
@ -435,7 +435,7 @@ pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tc
.map_or(&[][..], |a| a.args)
.iter()
.filter_map(|a| match a {
hir::GenericArg::Type(ty) => Some(ty.as_unambig_ty()),
GenericArg::Type(ty) => Some(ty.as_unambig_ty()),
_ => None,
})
}
@ -3709,3 +3709,21 @@ pub fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
true
}
}
/// Peel `Option<…>` from `hir_ty` as long as the HIR name is `Option` and it corresponds to the
/// `core::Option<_>` type.
pub fn peel_hir_ty_options<'tcx>(cx: &LateContext<'tcx>, mut hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
let Some(option_def_id) = cx.tcx.get_diagnostic_item(sym::Option) else {
return hir_ty;
};
while let TyKind::Path(QPath::Resolved(None, path)) = hir_ty.kind
&& let Some(segment) = path.segments.last()
&& segment.ident.name == sym::Option
&& let Res::Def(DefKind::Enum, def_id) = segment.res
&& def_id == option_def_id
&& let [GenericArg::Type(arg_ty)] = segment.args().args
{
hir_ty = arg_ty.as_unambig_ty();
}
hir_ty
}