about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/create_dir.rs51
-rw-r--r--clippy_lints/src/lib.rs4
-rw-r--r--clippy_lints/src/utils/paths.rs1
-rw-r--r--src/lintlist/mod.rs7
-rw-r--r--tests/ui/create_dir.fixed17
-rw-r--r--tests/ui/create_dir.rs17
-rw-r--r--tests/ui/create_dir.stderr16
8 files changed, 114 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 99a8b1a6293..64f9379b303 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1547,6 +1547,7 @@ Released 2018-09-13
 [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
 [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
 [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
+[`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir
 [`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
 [`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro
 [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs
new file mode 100644
index 00000000000..4002fb655a5
--- /dev/null
+++ b/clippy_lints/src/create_dir.rs
@@ -0,0 +1,51 @@
+use crate::utils::{match_def_path, paths, snippet, span_lint_and_sugg};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead.
+    ///
+    /// **Why is this bad?** Sometimes `std::fs::crate_dir` is mistakenly chosen over `std::fs::create_dir_all`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// std::fs::create_dir("foo");
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// std::fs::create_dir_all("foo");
+    /// ```
+    pub CREATE_DIR,
+    restriction,
+    "calling `std::fs::create_dir` instead of `std::fs::create_dir_all`"
+}
+
+declare_lint_pass!(CreateDir => [CREATE_DIR]);
+
+impl LateLintPass<'_> for CreateDir {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if_chain! {
+            if let ExprKind::Call(ref func, ref args) = expr.kind;
+            if let ExprKind::Path(ref path) = func.kind;
+            if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
+            if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR);
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    CREATE_DIR,
+                    expr.span,
+                    "calling `std::fs::create_dir` where there may be a better way",
+                    "consider calling `std::fs::create_dir_all` instead",
+                    format!("create_dir_all({})", snippet(cx, args[0].span, "..")),
+                    Applicability::MaybeIncorrect,
+                )
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 0eb1d331366..2020ef78509 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -170,6 +170,7 @@ mod collapsible_if;
 mod comparison_chain;
 mod copies;
 mod copy_iterator;
+mod create_dir;
 mod dbg_macro;
 mod default_trait_access;
 mod dereference;
@@ -513,6 +514,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &copies::MATCH_SAME_ARMS,
         &copies::SAME_FUNCTIONS_IN_IF_CONDITION,
         &copy_iterator::COPY_ITERATOR,
+        &create_dir::CREATE_DIR,
         &dbg_macro::DBG_MACRO,
         &default_trait_access::DEFAULT_TRAIT_ACCESS,
         &dereference::EXPLICIT_DEREF_METHODS,
@@ -1044,6 +1046,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
     store.register_early_pass(|| box precedence::Precedence);
     store.register_early_pass(|| box needless_continue::NeedlessContinue);
+    store.register_late_pass(|| box create_dir::CreateDir);
     store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
     store.register_early_pass(|| box redundant_static_lifetimes::RedundantStaticLifetimes);
     store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata);
@@ -1107,6 +1110,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
         LintId::of(&arithmetic::INTEGER_ARITHMETIC),
         LintId::of(&as_conversions::AS_CONVERSIONS),
+        LintId::of(&create_dir::CREATE_DIR),
         LintId::of(&dbg_macro::DBG_MACRO),
         LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
         LintId::of(&exit::EXIT),
diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs
index d44854aefe9..65320d6a0e0 100644
--- a/clippy_lints/src/utils/paths.rs
+++ b/clippy_lints/src/utils/paths.rs
@@ -110,6 +110,7 @@ pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"];
 pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
 pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"];
 pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"];
+pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
 pub const STD_MEM_TRANSMUTE: [&str; 3] = ["std", "mem", "transmute"];
 pub const STD_PTR_NULL: [&str; 3] = ["std", "ptr", "null"];
 pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs
index dff19ef440f..6697835e950 100644
--- a/src/lintlist/mod.rs
+++ b/src/lintlist/mod.rs
@@ -298,6 +298,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "copy_iterator",
     },
     Lint {
+        name: "create_dir",
+        group: "restriction",
+        desc: "calling `std::fs::create_dir` instead of `std::fs::create_dir_all`",
+        deprecation: None,
+        module: "create_dir",
+    },
+    Lint {
         name: "crosspointer_transmute",
         group: "complexity",
         desc: "transmutes that have to or from types that are a pointer to the other",
diff --git a/tests/ui/create_dir.fixed b/tests/ui/create_dir.fixed
new file mode 100644
index 00000000000..8ed53a56ac0
--- /dev/null
+++ b/tests/ui/create_dir.fixed
@@ -0,0 +1,17 @@
+// run-rustfix
+#![allow(unused_must_use)]
+#![warn(clippy::create_dir)]
+
+use std::fs::create_dir_all;
+
+fn create_dir() {}
+
+fn main() {
+    // Should be warned
+    create_dir_all("foo");
+    create_dir_all("bar").unwrap();
+
+    // Shouldn't be warned
+    create_dir();
+    std::fs::create_dir_all("foobar");
+}
diff --git a/tests/ui/create_dir.rs b/tests/ui/create_dir.rs
new file mode 100644
index 00000000000..19c8fc24ba2
--- /dev/null
+++ b/tests/ui/create_dir.rs
@@ -0,0 +1,17 @@
+// run-rustfix
+#![allow(unused_must_use)]
+#![warn(clippy::create_dir)]
+
+use std::fs::create_dir_all;
+
+fn create_dir() {}
+
+fn main() {
+    // Should be warned
+    std::fs::create_dir("foo");
+    std::fs::create_dir("bar").unwrap();
+
+    // Shouldn't be warned
+    create_dir();
+    std::fs::create_dir_all("foobar");
+}
diff --git a/tests/ui/create_dir.stderr b/tests/ui/create_dir.stderr
new file mode 100644
index 00000000000..67298fc4709
--- /dev/null
+++ b/tests/ui/create_dir.stderr
@@ -0,0 +1,16 @@
+error: calling `std::fs::create_dir` where there may be a better way
+  --> $DIR/create_dir.rs:11:5
+   |
+LL |     std::fs::create_dir("foo");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("foo")`
+   |
+   = note: `-D clippy::create-dir` implied by `-D warnings`
+
+error: calling `std::fs::create_dir` where there may be a better way
+  --> $DIR/create_dir.rs:12:5
+   |
+LL |     std::fs::create_dir("bar").unwrap();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `std::fs::create_dir_all` instead: `create_dir_all("bar")`
+
+error: aborting due to 2 previous errors
+