1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::source::{snippet_opt, snippet_with_applicability};
3 use clippy_utils::ty::{is_type_diagnostic_item, match_type};
4 use clippy_utils::{match_def_path, paths};
5 use if_chain::if_chain;
6 use rustc_errors::Applicability;
7 use rustc_hir::{Expr, ExprKind};
8 use rustc_lint::{LateContext, LateLintPass};
9 use rustc_session::{declare_lint_pass, declare_tool_lint};
12 declare_clippy_lint! {
14 /// Checks for non-octal values used to set Unix file permissions.
16 /// ### Why is this bad?
17 /// They will be converted into octal, creating potentially
18 /// unintended file permissions.
22 /// use std::fs::OpenOptions;
23 /// use std::os::unix::fs::OpenOptionsExt;
25 /// let mut options = OpenOptions::new();
26 /// options.mode(644);
30 /// use std::fs::OpenOptions;
31 /// use std::os::unix::fs::OpenOptionsExt;
33 /// let mut options = OpenOptions::new();
34 /// options.mode(0o644);
36 #[clippy::version = "1.53.0"]
37 pub NON_OCTAL_UNIX_PERMISSIONS,
39 "use of non-octal value to set unix file permissions, which will be translated into octal"
42 declare_lint_pass!(NonOctalUnixPermissions => [NON_OCTAL_UNIX_PERMISSIONS]);
44 impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
45 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
47 ExprKind::MethodCall(path, func, [param], _) => {
48 let obj_ty = cx.typeck_results().expr_ty(func).peel_refs();
51 if (path.ident.name == sym!(mode)
52 && (match_type(cx, obj_ty, &paths::OPEN_OPTIONS)
53 || is_type_diagnostic_item(cx, obj_ty, sym::DirBuilder)))
54 || (path.ident.name == sym!(set_mode) && match_type(cx, obj_ty, &paths::PERMISSIONS));
55 if let ExprKind::Lit(_) = param.kind;
58 let Some(snip) = snippet_opt(cx, param.span) else {
62 if !snip.starts_with("0o") {
63 show_error(cx, param);
68 ExprKind::Call(func, [param]) => {
70 if let ExprKind::Path(ref path) = func.kind;
71 if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
72 if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE);
73 if let ExprKind::Lit(_) = param.kind;
74 if let Some(snip) = snippet_opt(cx, param.span);
75 if !snip.starts_with("0o");
77 show_error(cx, param);
86 fn show_error(cx: &LateContext<'_>, param: &Expr<'_>) {
87 let mut applicability = Applicability::MachineApplicable;
90 NON_OCTAL_UNIX_PERMISSIONS,
92 "using a non-octal value to set unix file permissions",
93 "consider using an octal literal instead",
96 snippet_with_applicability(cx, param.span, "0o..", &mut applicability,),