Improve [std|alloc]_instead_of_[alloc|core] lints

* Don't call `TyCtxt::crate_name` unless necessary
* Don't lint on `use std::env`
* Only lint once on `use std::vec`
This commit is contained in:
Jason Newcomb
2022-07-24 20:17:55 -04:00
parent 20e4204730
commit 6bc024df18
4 changed files with 80 additions and 52 deletions

View File

@@ -916,7 +916,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; 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(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(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports)); store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default()));
// add lints here, do not remove this comment, it's used in `new_lint` // add lints here, do not remove this comment, it's used in `new_lint`
} }

View File

@@ -1,8 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use rustc_hir::{def::Res, HirId, Path, PathSegment}; use rustc_hir::{def::Res, HirId, Path, PathSegment};
use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, symbol::kw, Symbol}; use rustc_span::{sym, symbol::kw, Span};
declare_clippy_lint! { declare_clippy_lint! {
/// ### What it does /// ### What it does
@@ -81,39 +81,55 @@ declare_clippy_lint! {
"type is imported from alloc when available in core" "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]); #[derive(Default)]
pub struct StdReexports {
// Paths which can be either a module or a macro (e.g. `std::env`) will cause this check to happen
// twice. First for the mod, second for the macro. This is used to avoid the lint reporting for the macro
// when the path could be also be used to access the module.
prev_span: Span,
}
impl_lint_pass!(StdReexports => [STD_INSTEAD_OF_CORE, STD_INSTEAD_OF_ALLOC, ALLOC_INSTEAD_OF_CORE]);
impl<'tcx> LateLintPass<'tcx> for StdReexports { impl<'tcx> LateLintPass<'tcx> for StdReexports {
fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) { fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) {
// std_instead_of_core if let Res::Def(_, def_id) = path.res
check_path(cx, path, sym::std, sym::core, STD_INSTEAD_OF_CORE); && let Some(first_segment) = get_first_segment(path)
// std_instead_of_alloc {
check_path(cx, path, sym::std, sym::alloc, STD_INSTEAD_OF_ALLOC); let (lint, msg, help) = match first_segment.ident.name {
// alloc_instead_of_core sym::std => match cx.tcx.crate_name(def_id.krate) {
check_path(cx, path, sym::alloc, sym::core, ALLOC_INSTEAD_OF_CORE); sym::core => (
} STD_INSTEAD_OF_CORE,
} "used import from `std` instead of `core`",
"consider importing the item from `core`",
fn check_path(cx: &LateContext<'_>, path: &Path<'_>, krate: Symbol, suggested_crate: Symbol, lint: &'static Lint) { ),
if_chain! { sym::alloc => (
// check if path resolves to the suggested crate. STD_INSTEAD_OF_ALLOC,
if let Res::Def(_, def_id) = path.res; "used import from `std` instead of `alloc`",
if suggested_crate == cx.tcx.crate_name(def_id.krate); "consider importing the item from `alloc`",
),
// 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); self.prev_span = path.span;
return;
// check if the path matches the crate we want to suggest the other path for. },
if krate == path_root_segment.ident.name; },
then { sym::alloc => {
span_lint_and_help( if cx.tcx.crate_name(def_id.krate) == sym::core {
cx, (
lint, ALLOC_INSTEAD_OF_CORE,
path.span, "used import from `alloc` instead of `core`",
&format!("used import from `{}` instead of `{}`", krate, suggested_crate), "consider importing the item from `core`",
None, )
&format!("consider importing the item from `{}`", suggested_crate), } else {
); self.prev_span = path.span;
return;
}
},
_ => return,
};
if path.span != self.prev_span {
span_lint_and_help(cx, lint, path.span, msg, None, help);
self.prev_span = path.span;
}
} }
} }
} }
@@ -123,12 +139,10 @@ fn check_path(cx: &LateContext<'_>, path: &Path<'_>, krate: Symbol, suggested_cr
/// If this is a global path (such as `::std::fmt::Debug`), then the segment after [`kw::PathRoot`] /// If this is a global path (such as `::std::fmt::Debug`), then the segment after [`kw::PathRoot`]
/// is returned. /// is returned.
fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
let segment = path.segments.first()?; match path.segments {
// A global path will have PathRoot as the first segment. In this case, return the segment after.
// A global path will have PathRoot as the first segment. In this case, return the segment after. [x, y, ..] if x.ident.name == kw::PathRoot => Some(y),
if segment.ident.name == kw::PathRoot { [x, ..] => Some(x),
path.segments.get(1) _ => None,
} else {
Some(segment)
} }
} }

View File

@@ -9,6 +9,8 @@ fn std_instead_of_core() {
use std::hash::Hasher; use std::hash::Hasher;
// Absolute path // Absolute path
use ::std::hash::Hash; use ::std::hash::Hash;
// Don't lint on `env` macro
use std::env;
// Multiple imports // Multiple imports
use std::fmt::{Debug, Result}; use std::fmt::{Debug, Result};
@@ -20,10 +22,14 @@ fn std_instead_of_core() {
// Types // Types
let cell = std::cell::Cell::new(8u32); let cell = std::cell::Cell::new(8u32);
let cell_absolute = ::std::cell::Cell::new(8u32); let cell_absolute = ::std::cell::Cell::new(8u32);
let _ = std::env!("PATH");
} }
#[warn(clippy::std_instead_of_alloc)] #[warn(clippy::std_instead_of_alloc)]
fn std_instead_of_alloc() { fn std_instead_of_alloc() {
// Only lint once.
use std::vec;
use std::vec::Vec; use std::vec::Vec;
} }

View File

@@ -16,7 +16,7 @@ LL | use ::std::hash::Hash;
= help: consider importing the item from `core` = help: consider importing the item from `core`
error: used import from `std` instead of `core` error: used import from `std` instead of `core`
--> $DIR/std_instead_of_core.rs:14:20 --> $DIR/std_instead_of_core.rs:16:20
| |
LL | use std::fmt::{Debug, Result}; LL | use std::fmt::{Debug, Result};
| ^^^^^ | ^^^^^
@@ -24,7 +24,7 @@ LL | use std::fmt::{Debug, Result};
= help: consider importing the item from `core` = help: consider importing the item from `core`
error: used import from `std` instead of `core` error: used import from `std` instead of `core`
--> $DIR/std_instead_of_core.rs:14:27 --> $DIR/std_instead_of_core.rs:16:27
| |
LL | use std::fmt::{Debug, Result}; LL | use std::fmt::{Debug, Result};
| ^^^^^^ | ^^^^^^
@@ -32,7 +32,7 @@ LL | use std::fmt::{Debug, Result};
= help: consider importing the item from `core` = help: consider importing the item from `core`
error: used import from `std` instead of `core` error: used import from `std` instead of `core`
--> $DIR/std_instead_of_core.rs:17:15 --> $DIR/std_instead_of_core.rs:19:15
| |
LL | let ptr = std::ptr::null::<u32>(); LL | let ptr = std::ptr::null::<u32>();
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +40,7 @@ LL | let ptr = std::ptr::null::<u32>();
= help: consider importing the item from `core` = help: consider importing the item from `core`
error: used import from `std` instead of `core` error: used import from `std` instead of `core`
--> $DIR/std_instead_of_core.rs:18:19 --> $DIR/std_instead_of_core.rs:20:19
| |
LL | let ptr_mut = ::std::ptr::null_mut::<usize>(); LL | let ptr_mut = ::std::ptr::null_mut::<usize>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL | let ptr_mut = ::std::ptr::null_mut::<usize>();
= help: consider importing the item from `core` = help: consider importing the item from `core`
error: used import from `std` instead of `core` error: used import from `std` instead of `core`
--> $DIR/std_instead_of_core.rs:21:16 --> $DIR/std_instead_of_core.rs:23:16
| |
LL | let cell = std::cell::Cell::new(8u32); LL | let cell = std::cell::Cell::new(8u32);
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL | let cell = std::cell::Cell::new(8u32);
= help: consider importing the item from `core` = help: consider importing the item from `core`
error: used import from `std` instead of `core` error: used import from `std` instead of `core`
--> $DIR/std_instead_of_core.rs:22:25 --> $DIR/std_instead_of_core.rs:24:25
| |
LL | let cell_absolute = ::std::cell::Cell::new(8u32); LL | let cell_absolute = ::std::cell::Cell::new(8u32);
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
@@ -64,16 +64,24 @@ LL | let cell_absolute = ::std::cell::Cell::new(8u32);
= help: consider importing the item from `core` = help: consider importing the item from `core`
error: used import from `std` instead of `alloc` error: used import from `std` instead of `alloc`
--> $DIR/std_instead_of_core.rs:27:9 --> $DIR/std_instead_of_core.rs:32:9
| |
LL | use std::vec::Vec; LL | use std::vec;
| ^^^^^^^^^^^^^ | ^^^^^^^^
| |
= note: `-D clippy::std-instead-of-alloc` implied by `-D warnings` = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings`
= help: consider importing the item from `alloc` = help: consider importing the item from `alloc`
error: used import from `std` instead of `alloc`
--> $DIR/std_instead_of_core.rs:33:9
|
LL | use std::vec::Vec;
| ^^^^^^^^^^^^^
|
= help: consider importing the item from `alloc`
error: used import from `alloc` instead of `core` error: used import from `alloc` instead of `core`
--> $DIR/std_instead_of_core.rs:32:9 --> $DIR/std_instead_of_core.rs:38:9
| |
LL | use alloc::slice::from_ref; LL | use alloc::slice::from_ref;
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
@@ -81,5 +89,5 @@ LL | use alloc::slice::from_ref;
= note: `-D clippy::alloc-instead-of-core` implied by `-D warnings` = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings`
= help: consider importing the item from `core` = help: consider importing the item from `core`
error: aborting due to 10 previous errors error: aborting due to 11 previous errors