Skip to content

Add std_instead_of_core, std_instead_of_alloc, alloc_instead_of_core #9103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions clippy_lints/src/lib.register_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions clippy_lints/src/lib.register_restriction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
2 changes: 2 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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`
}

Expand Down
134 changes: 134 additions & 0 deletions clippy_lints/src/std_instead_of_core.rs
Original file line number Diff line number Diff line change
@@ -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)
}
}
39 changes: 39 additions & 0 deletions tests/ui/std_instead_of_core.rs
Original file line number Diff line number Diff line change
@@ -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();
}
85 changes: 85 additions & 0 deletions tests/ui/std_instead_of_core.stderr
Original file line number Diff line number Diff line change
@@ -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