]>
Commit | Line | Data |
---|---|---|
cdc7bbd5 XL |
1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
2 | use clippy_utils::source::{snippet_opt, snippet_with_applicability}; | |
cdc7bbd5 XL |
3 | use clippy_utils::{match_def_path, paths}; |
4 | use if_chain::if_chain; | |
5 | use rustc_errors::Applicability; | |
6 | use rustc_hir::{Expr, ExprKind}; | |
7 | use rustc_lint::{LateContext, LateLintPass}; | |
8 | use rustc_session::{declare_lint_pass, declare_tool_lint}; | |
2b03887a | 9 | use rustc_span::sym; |
cdc7bbd5 XL |
10 | |
11 | declare_clippy_lint! { | |
94222f64 XL |
12 | /// ### What it does |
13 | /// Checks for non-octal values used to set Unix file permissions. | |
cdc7bbd5 | 14 | /// |
94222f64 XL |
15 | /// ### Why is this bad? |
16 | /// They will be converted into octal, creating potentially | |
cdc7bbd5 XL |
17 | /// unintended file permissions. |
18 | /// | |
94222f64 | 19 | /// ### Example |
cdc7bbd5 XL |
20 | /// ```rust,ignore |
21 | /// use std::fs::OpenOptions; | |
22 | /// use std::os::unix::fs::OpenOptionsExt; | |
23 | /// | |
24 | /// let mut options = OpenOptions::new(); | |
25 | /// options.mode(644); | |
26 | /// ``` | |
27 | /// Use instead: | |
28 | /// ```rust,ignore | |
29 | /// use std::fs::OpenOptions; | |
30 | /// use std::os::unix::fs::OpenOptionsExt; | |
31 | /// | |
32 | /// let mut options = OpenOptions::new(); | |
33 | /// options.mode(0o644); | |
34 | /// ``` | |
a2a8927a | 35 | #[clippy::version = "1.53.0"] |
cdc7bbd5 XL |
36 | pub NON_OCTAL_UNIX_PERMISSIONS, |
37 | correctness, | |
38 | "use of non-octal value to set unix file permissions, which will be translated into octal" | |
39 | } | |
40 | ||
41 | declare_lint_pass!(NonOctalUnixPermissions => [NON_OCTAL_UNIX_PERMISSIONS]); | |
42 | ||
5099ac24 | 43 | impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { |
cdc7bbd5 XL |
44 | fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { |
45 | match &expr.kind { | |
f2b60f7d | 46 | ExprKind::MethodCall(path, func, [param], _) => { |
cdc7bbd5 | 47 | if_chain! { |
ed00b5ec | 48 | if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def(); |
cdc7bbd5 | 49 | if (path.ident.name == sym!(mode) |
ed00b5ec FG |
50 | && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::FsOpenOptions | sym::DirBuilder))) |
51 | || (path.ident.name == sym!(set_mode) | |
52 | && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())); | |
cdc7bbd5 | 53 | if let ExprKind::Lit(_) = param.kind; |
ed00b5ec | 54 | if param.span.eq_ctxt(expr.span); |
cdc7bbd5 XL |
55 | |
56 | then { | |
2b03887a FG |
57 | let Some(snip) = snippet_opt(cx, param.span) else { |
58 | return | |
cdc7bbd5 XL |
59 | }; |
60 | ||
61 | if !snip.starts_with("0o") { | |
62 | show_error(cx, param); | |
63 | } | |
64 | } | |
65 | } | |
66 | }, | |
67 | ExprKind::Call(func, [param]) => { | |
68 | if_chain! { | |
69 | if let ExprKind::Path(ref path) = func.kind; | |
70 | if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); | |
71 | if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE); | |
72 | if let ExprKind::Lit(_) = param.kind; | |
ed00b5ec | 73 | if param.span.eq_ctxt(expr.span); |
2b03887a FG |
74 | if let Some(snip) = snippet_opt(cx, param.span); |
75 | if !snip.starts_with("0o"); | |
cdc7bbd5 | 76 | then { |
2b03887a | 77 | show_error(cx, param); |
cdc7bbd5 XL |
78 | } |
79 | } | |
80 | }, | |
81 | _ => {}, | |
82 | }; | |
83 | } | |
84 | } | |
85 | ||
86 | fn show_error(cx: &LateContext<'_>, param: &Expr<'_>) { | |
87 | let mut applicability = Applicability::MachineApplicable; | |
88 | span_lint_and_sugg( | |
89 | cx, | |
90 | NON_OCTAL_UNIX_PERMISSIONS, | |
91 | param.span, | |
92 | "using a non-octal value to set unix file permissions", | |
93 | "consider using an octal literal instead", | |
94 | format!( | |
95 | "0o{}", | |
96 | snippet_with_applicability(cx, param.span, "0o..", &mut applicability,), | |
97 | ), | |
98 | applicability, | |
99 | ); | |
100 | } |