about summary refs log tree commit diff
diff options
context:
space:
mode:
authori509VCB <git@i509.me>2022-07-01 23:59:03 -0500
committeri509VCB <git@i509.me>2022-07-14 16:05:52 -0500
commit2f825db5789678965861e5109aa30b9b9e2a7b4c (patch)
tree8bd2e20552ae5c8f08dfbe02b8a181ddb230beda
parent0f5a38f2d6fa3f241ab4ce79f9c927659da7f208 (diff)
downloadrust-2f825db5789678965861e5109aa30b9b9e2a7b4c.tar.gz
rust-2f825db5789678965861e5109aa30b9b9e2a7b4c.zip
std_instead_of_core, std_instead_of_alloc, alloc_instead_of_core
-rw-r--r--CHANGELOG.md3
-rw-r--r--clippy_lints/src/lib.register_lints.rs3
-rw-r--r--clippy_lints/src/lib.register_restriction.rs3
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--clippy_lints/src/std_instead_of_core.rs134
-rw-r--r--tests/ui/std_instead_of_core.rs39
-rw-r--r--tests/ui/std_instead_of_core.stderr85
7 files changed, 269 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 201929ec11c..920d397add7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3432,6 +3432,7 @@ Released 2018-09-13
 <!-- lint disable no-unused-definitions -->
 <!-- begin autogenerated links to lint list -->
 [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
+[`alloc_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#alloc_instead_of_core
 [`allow_attributes_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason
 [`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range
 [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
@@ -3901,6 +3902,8 @@ Released 2018-09-13
 [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
 [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
 [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
+[`std_instead_of_alloc`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_alloc
+[`std_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_core
 [`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string
 [`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
 [`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index ceb8470657f..91d27bf526d 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -497,6 +497,9 @@ store.register_lints(&[
     size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
     slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
     stable_sort_primitive::STABLE_SORT_PRIMITIVE,
+    std_instead_of_core::ALLOC_INSTEAD_OF_CORE,
+    std_instead_of_core::STD_INSTEAD_OF_ALLOC,
+    std_instead_of_core::STD_INSTEAD_OF_CORE,
     strings::STRING_ADD,
     strings::STRING_ADD_ASSIGN,
     strings::STRING_FROM_UTF8_AS_BYTES,
diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs
index 88d43c8989f..43f1c892eb9 100644
--- a/clippy_lints/src/lib.register_restriction.rs
+++ b/clippy_lints/src/lib.register_restriction.rs
@@ -66,6 +66,9 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(shadow::SHADOW_SAME),
     LintId::of(shadow::SHADOW_UNRELATED),
     LintId::of(single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES),
+    LintId::of(std_instead_of_core::ALLOC_INSTEAD_OF_CORE),
+    LintId::of(std_instead_of_core::STD_INSTEAD_OF_ALLOC),
+    LintId::of(std_instead_of_core::STD_INSTEAD_OF_CORE),
     LintId::of(strings::STRING_ADD),
     LintId::of(strings::STRING_SLICE),
     LintId::of(strings::STRING_TO_STRING),
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 1604d1078ee..4f9db4eb5ae 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -365,6 +365,7 @@ mod single_component_path_imports;
 mod size_of_in_element_count;
 mod slow_vector_initialization;
 mod stable_sort_primitive;
+mod std_instead_of_core;
 mod strings;
 mod strlen_on_c_strings;
 mod suspicious_operation_groupings;
@@ -915,6 +916,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
     store.register_late_pass(move || Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
     store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
+    store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs
new file mode 100644
index 00000000000..56f2a7bae15
--- /dev/null
+++ b/clippy_lints/src/std_instead_of_core.rs
@@ -0,0 +1,134 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_hir::{def::Res, HirId, Path, PathSegment};
+use rustc_lint::{LateContext, LateLintPass, Lint};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, symbol::kw, Symbol};
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Finds items imported through `std` when available through `core`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Crates which have `no_std` compatibility may wish to ensure types are imported from core to ensure
+    /// disabling `std` does not cause the crate to fail to compile. This lint is also useful for crates
+    /// migrating to become `no_std` compatible.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::hash::Hasher;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use core::hash::Hasher;
+    /// ```
+    #[clippy::version = "1.64.0"]
+    pub STD_INSTEAD_OF_CORE,
+    restriction,
+    "type is imported from std when available in core"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Finds items imported through `std` when available through `alloc`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Crates which have `no_std` compatibility and require alloc may wish to ensure types are imported from
+    /// alloc to ensure disabling `std` does not cause the crate to fail to compile. This lint is also useful
+    /// for crates migrating to become `no_std` compatible.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::vec::Vec;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # extern crate alloc;
+    /// use alloc::vec::Vec;
+    /// ```
+    #[clippy::version = "1.64.0"]
+    pub STD_INSTEAD_OF_ALLOC,
+    restriction,
+    "type is imported from std when available in alloc"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Finds items imported through `alloc` when available through `core`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Crates which have `no_std` compatibility and may optionally require alloc may wish to ensure types are
+    /// imported from alloc to ensure disabling `alloc` does not cause the crate to fail to compile. This lint
+    /// is also useful for crates migrating to become `no_std` compatible.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # extern crate alloc;
+    /// use alloc::slice::from_ref;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use core::slice::from_ref;
+    /// ```
+    #[clippy::version = "1.64.0"]
+    pub ALLOC_INSTEAD_OF_CORE,
+    restriction,
+    "type is imported from alloc when available in core"
+}
+
+declare_lint_pass!(StdReexports => [STD_INSTEAD_OF_CORE, STD_INSTEAD_OF_ALLOC, ALLOC_INSTEAD_OF_CORE]);
+
+impl<'tcx> LateLintPass<'tcx> for StdReexports {
+    fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) {
+        // std_instead_of_core
+        check_path(cx, path, sym::std, sym::core, STD_INSTEAD_OF_CORE);
+        // std_instead_of_alloc
+        check_path(cx, path, sym::std, sym::alloc, STD_INSTEAD_OF_ALLOC);
+        // alloc_instead_of_core
+        check_path(cx, path, sym::alloc, sym::core, ALLOC_INSTEAD_OF_CORE);
+    }
+}
+
+fn check_path(cx: &LateContext<'_>, path: &Path<'_>, krate: Symbol, suggested_crate: Symbol, lint: &'static Lint) {
+    if_chain! {
+        // check if path resolves to the suggested crate.
+        if let Res::Def(_, def_id) = path.res;
+        if suggested_crate == cx.tcx.crate_name(def_id.krate);
+
+        // check if the first segment of the path is the crate we want to identify
+        if let Some(path_root_segment) = get_first_segment(path);
+
+        // check if the path matches the crate we want to suggest the other path for.
+        if krate == path_root_segment.ident.name;
+        then {
+            span_lint_and_help(
+                cx,
+                lint,
+                path.span,
+                &format!("used import from `{}` instead of `{}`", krate, suggested_crate),
+                None,
+                &format!("consider importing the item from `{}`", suggested_crate),
+            );
+        }
+    }
+}
+
+/// Returns the first named segment of a [`Path`].
+///
+/// If this is a global path (such as `::std::fmt::Debug`), then the segment after [`kw::PathRoot`]
+/// is returned.
+fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
+    let segment = path.segments.first()?;
+
+    // A global path will have PathRoot as the first segment. In this case, return the segment after.
+    if segment.ident.name == kw::PathRoot {
+        path.segments.get(1)
+    } else {
+        Some(segment)
+    }
+}
diff --git a/tests/ui/std_instead_of_core.rs b/tests/ui/std_instead_of_core.rs
new file mode 100644
index 00000000000..74f05ec1f65
--- /dev/null
+++ b/tests/ui/std_instead_of_core.rs
@@ -0,0 +1,39 @@
+#![warn(clippy::std_instead_of_core)]
+#![allow(unused_imports)]
+
+extern crate alloc;
+
+#[warn(clippy::std_instead_of_core)]
+fn std_instead_of_core() {
+    // Regular import
+    use std::hash::Hasher;
+    // Absolute path
+    use ::std::hash::Hash;
+
+    // Multiple imports
+    use std::fmt::{Debug, Result};
+
+    // Function calls
+    let ptr = std::ptr::null::<u32>();
+    let ptr_mut = ::std::ptr::null_mut::<usize>();
+
+    // Types
+    let cell = std::cell::Cell::new(8u32);
+    let cell_absolute = ::std::cell::Cell::new(8u32);
+}
+
+#[warn(clippy::std_instead_of_alloc)]
+fn std_instead_of_alloc() {
+    use std::vec::Vec;
+}
+
+#[warn(clippy::alloc_instead_of_core)]
+fn alloc_instead_of_core() {
+    use alloc::slice::from_ref;
+}
+
+fn main() {
+    std_instead_of_core();
+    std_instead_of_alloc();
+    alloc_instead_of_core();
+}
diff --git a/tests/ui/std_instead_of_core.stderr b/tests/ui/std_instead_of_core.stderr
new file mode 100644
index 00000000000..9f1644835c1
--- /dev/null
+++ b/tests/ui/std_instead_of_core.stderr
@@ -0,0 +1,85 @@
+error: used import from `std` instead of `core`
+  --> $DIR/std_instead_of_core.rs:9:9
+   |
+LL |     use std::hash::Hasher;
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::std-instead-of-core` implied by `-D warnings`
+   = help: consider importing the item from `core`
+
+error: used import from `std` instead of `core`
+  --> $DIR/std_instead_of_core.rs:11:9
+   |
+LL |     use ::std::hash::Hash;
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider importing the item from `core`
+
+error: used import from `std` instead of `core`
+  --> $DIR/std_instead_of_core.rs:14:20
+   |
+LL |     use std::fmt::{Debug, Result};
+   |                    ^^^^^
+   |
+   = help: consider importing the item from `core`
+
+error: used import from `std` instead of `core`
+  --> $DIR/std_instead_of_core.rs:14:27
+   |
+LL |     use std::fmt::{Debug, Result};
+   |                           ^^^^^^
+   |
+   = help: consider importing the item from `core`
+
+error: used import from `std` instead of `core`
+  --> $DIR/std_instead_of_core.rs:17:15
+   |
+LL |     let ptr = std::ptr::null::<u32>();
+   |               ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider importing the item from `core`
+
+error: used import from `std` instead of `core`
+  --> $DIR/std_instead_of_core.rs:18:19
+   |
+LL |     let ptr_mut = ::std::ptr::null_mut::<usize>();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider importing the item from `core`
+
+error: used import from `std` instead of `core`
+  --> $DIR/std_instead_of_core.rs:21:16
+   |
+LL |     let cell = std::cell::Cell::new(8u32);
+   |                ^^^^^^^^^^^^^^^
+   |
+   = help: consider importing the item from `core`
+
+error: used import from `std` instead of `core`
+  --> $DIR/std_instead_of_core.rs:22:25
+   |
+LL |     let cell_absolute = ::std::cell::Cell::new(8u32);
+   |                         ^^^^^^^^^^^^^^^^^
+   |
+   = help: consider importing the item from `core`
+
+error: used import from `std` instead of `alloc`
+  --> $DIR/std_instead_of_core.rs:27:9
+   |
+LL |     use std::vec::Vec;
+   |         ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings`
+   = help: consider importing the item from `alloc`
+
+error: used import from `alloc` instead of `core`
+  --> $DIR/std_instead_of_core.rs:32:9
+   |
+LL |     use alloc::slice::from_ref;
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings`
+   = help: consider importing the item from `core`
+
+error: aborting due to 10 previous errors
+