1 use rustc_hir::{self as hir, intravisit, HirIdSet};
2 use rustc_lint::LateContext;
3 use rustc_middle::{hir::map::Map, ty};
4 use rustc_span::def_id::LocalDefId;
6 use clippy_utils::diagnostics::span_lint;
7 use clippy_utils::ty::type_is_unsafe_function;
8 use clippy_utils::{iter_input_pats, path_to_local};
10 use super::NOT_UNSAFE_PTR_ARG_DEREF;
12 pub(super) fn check_fn(
13 cx: &LateContext<'tcx>,
14 kind: intravisit::FnKind<'tcx>,
15 decl: &'tcx hir::FnDecl<'tcx>,
16 body: &'tcx hir::Body<'tcx>,
19 let unsafety = match kind {
20 intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }, _) => unsafety,
21 intravisit::FnKind::Method(_, sig, _) => sig.header.unsafety,
22 intravisit::FnKind::Closure => return,
25 check_raw_ptr(cx, unsafety, decl, body, cx.tcx.hir().local_def_id(hir_id));
28 pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
29 if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
30 let body = cx.tcx.hir().body(eid);
31 check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.def_id);
36 cx: &LateContext<'tcx>,
37 unsafety: hir::Unsafety,
38 decl: &'tcx hir::FnDecl<'tcx>,
39 body: &'tcx hir::Body<'tcx>,
42 let expr = &body.value;
43 if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(def_id) {
44 let raw_ptrs = iter_input_pats(decl, body)
45 .zip(decl.inputs.iter())
46 .filter_map(|(arg, ty)| raw_ptr_arg(arg, ty))
47 .collect::<HirIdSet>();
49 if !raw_ptrs.is_empty() {
50 let typeck_results = cx.tcx.typeck_body(body.id());
51 let mut v = DerefVisitor {
57 intravisit::walk_expr(&mut v, expr);
62 fn raw_ptr_arg(arg: &hir::Param<'_>, ty: &hir::Ty<'_>) -> Option<hir::HirId> {
63 if let (&hir::PatKind::Binding(_, id, _, _), &hir::TyKind::Ptr(_)) = (&arg.pat.kind, &ty.kind) {
70 struct DerefVisitor<'a, 'tcx> {
71 cx: &'a LateContext<'tcx>,
73 typeck_results: &'a ty::TypeckResults<'tcx>,
76 impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
79 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
81 hir::ExprKind::Call(f, args) => {
82 let ty = self.typeck_results.expr_ty(f);
84 if type_is_unsafe_function(self.cx, ty) {
90 hir::ExprKind::MethodCall(_, _, args, _) => {
91 let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap();
92 let base_type = self.cx.tcx.type_of(def_id);
94 if type_is_unsafe_function(self.cx, base_type) {
100 hir::ExprKind::Unary(hir::UnOp::Deref, ptr) => self.check_arg(ptr),
104 intravisit::walk_expr(self, expr);
107 fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
108 intravisit::NestedVisitorMap::None
112 impl<'a, 'tcx> DerefVisitor<'a, 'tcx> {
113 fn check_arg(&self, ptr: &hir::Expr<'_>) {
114 if let Some(id) = path_to_local(ptr) {
115 if self.ptrs.contains(&id) {
118 NOT_UNSAFE_PTR_ARG_DEREF,
120 "this public function might dereference a raw pointer but is not marked `unsafe`",