diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs index 0f7cbd503bcd..7f66b278b9d0 100644 --- a/clippy_lints/src/std_instead_of_core.rs +++ b/clippy_lints/src/std_instead_of_core.rs @@ -1,15 +1,17 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; -use clippy_utils::is_from_proc_macro; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::Msrv; -use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::DefId; -use rustc_hir::{Block, Body, HirId, Path, PathSegment, StabilityLevel, StableSince}; -use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; +use itertools::Itertools; +use rustc_errors::{Applicability, Diag}; +use rustc_hir::def::{DefKind, PerNS, Res}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; +use rustc_hir::{ + Block, HirId, Item, ItemKind, Mod, Path, PathSegment, StabilityLevel, StableSince, UseKind, find_attr, +}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{Span, sym}; +use rustc_span::{Ident, Span, Symbol, sym}; declare_clippy_lint! { /// ### What it does @@ -93,129 +95,224 @@ impl_lint_pass!(StdReexports => [ ]); pub struct StdReexports { - lint_points: Option<(Span, Vec)>, + /// Paths which could be candidates for linting. + lint_points: Vec, + /// Tracks nesting when linting a multi-import `use` statement. + item_context: Vec, + /// Tracks the availability of `core` and `alloc`, including possible renames. + crate_context: Vec, + /// Current Minimum Supported Rust Version. msrv: Msrv, } impl StdReexports { pub fn new(conf: &'static Conf) -> Self { Self { - lint_points: Option::default(), + lint_points: Vec::new(), + item_context: Vec::new(), + crate_context: Vec::new(), msrv: conf.msrv, } } - fn lint_if_finish(&mut self, cx: &LateContext<'_>, krate: Span, lint_point: LintPoint) { - match &mut self.lint_points { - Some((prev_krate, prev_lints)) if prev_krate.overlaps(krate) => { - prev_lints.push(lint_point); - }, - _ => emit_lints(cx, self.lint_points.replace((krate, vec![lint_point]))), + fn lint_if_finish(&mut self, cx: &LateContext<'_>, item: Span) { + while let Some(top) = self.item_context.pop_if(|top| !top.span.contains(item)) { + let count = match LintPoint::merge_top(&self.lint_points, &top) { + Some(merged) => { + self.lint_points.truncate(self.lint_points.len() - top.lint_points); + self.lint_points.push(merged); + 1 + }, + None => top.lint_points, + }; + + if let Some(next_top) = self.item_context.last_mut() { + next_top.lint_points += count; + } + } + + if self.item_context.is_empty() { + emit_lints(cx, self); } } } -#[derive(Debug)] -enum LintPoint { - Available(Span, &'static Lint, &'static str, &'static str), - Conflict, +#[derive(Clone, Copy, Debug)] +struct LintPoint { + first: Path<'static, DefId>, + last: Path<'static, PerNS>>, } impl<'tcx> LateLintPass<'tcx> for StdReexports { fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) { - if let Res::Def(def_kind, def_id) = path.res - && let Some(first_segment) = get_first_segment(path) - && is_stable(cx, def_id, self.msrv) - && !path.span.in_external_macro(cx.sess().source_map()) - && !is_from_proc_macro(cx, &first_segment.ident) - && !matches!(def_kind, DefKind::Macro(_)) - && let Some(last_segment) = path.segments.last() - && let Res::Def(DefKind::Mod, crate_def_id) = first_segment.res - && crate_def_id.is_crate_root() - { - let (lint, used_mod, replace_with) = match first_segment.ident.name { - sym::std => match cx.tcx.crate_name(def_id.krate) { - sym::core => (STD_INSTEAD_OF_CORE, "std", "core"), - sym::alloc => (STD_INSTEAD_OF_ALLOC, "std", "alloc"), - _ => { - self.lint_if_finish(cx, first_segment.ident.span, LintPoint::Conflict); - return; - }, - }, - sym::alloc if cx.tcx.crate_name(def_id.krate) == sym::core => (ALLOC_INSTEAD_OF_CORE, "alloc", "core"), - _ => { - self.lint_if_finish(cx, first_segment.ident.span, LintPoint::Conflict); - return; - }, - }; + if let Some(lint_point) = LintPoint::try_from_path(path) { + if let Some(last) = self.lint_points.last_mut() + && last.last.span == lint_point.last.span + { + last.last.res = PerNS { + value_ns: last.last.res.value_ns.or(lint_point.last.res.value_ns), + type_ns: last.last.res.type_ns.or(lint_point.last.res.type_ns), + macro_ns: last.last.res.macro_ns.or(lint_point.last.res.macro_ns), + }; + } else { + if let Some(top) = self.item_context.last_mut() + && top.span.contains(lint_point.last.span) + { + top.lint_points += 1; + } else { + let span = path + .segments + .iter() + .map(|s| s.ident.span) + .reduce(Span::to) + .unwrap_or(path.span); + self.lint_if_finish(cx, span); + self.item_context.push(ItemContext { span, lint_points: 1 }); + } + + self.lint_points.push(lint_point); + } + } + } + + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + self.lint_if_finish(cx, item.span); - self.lint_if_finish( - cx, - first_segment.ident.span, - LintPoint::Available(last_segment.ident.span, lint, used_mod, replace_with), - ); + match item.kind { + ItemKind::ExternCrate(Some(original), used) + | ItemKind::ExternCrate(None, used @ Ident { name: original, .. }) => { + let index = if cx + .tcx + .opt_local_parent(item.owner_id.def_id) + .is_some_and(LocalDefId::is_top_level_module) + { + 0 + } else { + self.crate_context.len() - 1 + }; + + match original { + sym::core => self.crate_context[index].core = Some(used.name), + sym::alloc => self.crate_context[index].alloc = Some(used.name), + _ => {}, + } + }, + ItemKind::Use(_path, UseKind::ListStem) => { + self.item_context.push(ItemContext { + span: item.span, + lint_points: 0, + }); + }, + _ => {}, } } - fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &Block<'tcx>) { - emit_lints(cx, self.lint_points.take()); + fn check_item_post(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + self.lint_if_finish(cx, item.span); } - fn check_body_post(&mut self, cx: &LateContext<'tcx>, _: &Body<'tcx>) { - emit_lints(cx, self.lint_points.take()); + fn check_crate(&mut self, cx: &LateContext<'tcx>) { + self.crate_context.push(CrateContext { + core: (!no_implicit_core(cx)).then_some(sym::core), + ..CrateContext::default() + }); } - fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { - emit_lints(cx, self.lint_points.take()); + fn check_crate_post(&mut self, _: &LateContext<'tcx>) { + self.crate_context.pop(); } -} -fn emit_lints(cx: &LateContext<'_>, lint_points: Option<(Span, Vec)>) { - let Some((krate_span, lint_points)) = lint_points else { - return; - }; - - let mut lint: Option<(&'static Lint, &'static str, &'static str)> = None; - let mut has_conflict = false; - for lint_point in &lint_points { - match lint_point { - LintPoint::Available(_, l, used_mod, replace_with) - if lint.is_none_or(|(prev_l, ..)| l.name == prev_l.name) => - { - lint = Some((l, used_mod, replace_with)); - }, - _ => { - has_conflict = true; - break; - }, - } + fn check_block(&mut self, _: &LateContext<'tcx>, _: &'tcx Block<'tcx>) { + self.crate_context + .push(self.crate_context.last().copied().unwrap_or_default()); } - if !has_conflict && let Some((lint, used_mod, replace_with)) = lint { - span_lint_and_sugg( - cx, - lint, - krate_span, - format!("used import from `{used_mod}` instead of `{replace_with}`"), - format!("consider importing the item from `{replace_with}`"), - (*replace_with).to_string(), - Applicability::MachineApplicable, - ); - return; + fn check_block_post(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { + self.lint_if_finish(cx, block.span); + self.crate_context.pop(); } - for lint_point in lint_points { - let LintPoint::Available(span, lint, used_mod, replace_with) = lint_point else { - continue; + fn check_mod(&mut self, _: &LateContext<'tcx>, _: &'tcx Mod<'tcx>, _: HirId) { + let first = self.crate_context[0]; + self.crate_context.pop(); + self.crate_context.push(first); + } +} + +fn emit_lints(cx: &LateContext<'_>, this: &mut StdReexports) { + let crate_context = this + .crate_context + .last() + .expect("crate_context must always contain at least one entry while linting a crate"); + + this.lint_points + .sort_by_key(|path| (path.first.span, path.first.res.krate, path.defined_in())); + + let mut drain = this + .lint_points + .drain(..) + .filter(|p| p.should_emit(cx, this.msrv)) + .peekable(); + + while let Some(path) = drain.next() { + let mut spans = drain + .peeking_take_while(|other| path.compatible_with(other)) + .map(|other| other.last.span) + .peekable(); + + let used_from = cx.tcx.crate_name(path.first.res.krate); + let defined_in = cx.tcx.crate_name(path.defined_in()); + + let (suggestion, lint, message, help) = match (used_from, defined_in) { + (sym::std, sym::core) => ( + crate_context.core, + STD_INSTEAD_OF_CORE, + "used import from `std` instead of `core`", + "consider importing the item from `core`", + ), + (sym::std, sym::alloc) => ( + crate_context.alloc, + STD_INSTEAD_OF_ALLOC, + "used import from `std` instead of `alloc`", + "consider importing the item from `alloc`", + ), + (sym::alloc, sym::core) => ( + crate_context.core, + ALLOC_INSTEAD_OF_CORE, + "used import from `alloc` instead of `core`", + "consider importing the item from `core`", + ), + _ => continue, + }; + + let should_suggest = path.last.span.contains(path.first.span) && path.first.res.is_crate_root(); + + let then = |diag: &mut Diag<'_, ()>| { + if should_suggest { + if let Some(suggestion) = suggestion { + diag.span_suggestion(path.first.span, help, suggestion, Applicability::MaybeIncorrect); + } else { + diag.help(help); + diag.help("consider adding an `extern crate` statement at the crate root"); + } + } else { + diag.help(help); + } }; - span_lint_and_help( - cx, - lint, - span, - format!("used import from `{used_mod}` instead of `{replace_with}`"), - None, - format!("consider importing the item from `{replace_with}`"), - ); + + if spans.peek().is_none() { + let span = if should_suggest { + path.first.span + } else { + path.last.span + }; + + span_lint_and_then(cx, lint, span, message, then); + } else { + for span in core::iter::once(path.last.span).chain(spans) { + span_lint_and_then(cx, lint, span, message, then); + } + } } } @@ -262,3 +359,102 @@ fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: Msrv) -> bool { } } } + +impl LintPoint { + fn try_from_path(path: &Path<'_>) -> Option { + let first = get_first_segment(path)?; + let last = path.segments.last()?; + + if !matches!(first.res, Res::Def(DefKind::Mod, _)) { + return None; + } + + Some(LintPoint { + first: Path { + span: first.ident.span, + res: first.res.opt_def_id()?, + segments: &[], + }, + last: Path { + span: last.ident.span, + res: { + let mut res = PerNS::default(); + res[path.res.ns()?] = Some(path.res.opt_def_id()?); + res + }, + segments: &[], + }, + }) + } + + /// Indicates that two [`LintPoint`]s could be merged. + fn compatible_with(&self, other: &Self) -> bool { + self.first.span == other.first.span + && self.first.res == other.first.res + && self + .last + .res + .present_items() + .all(|a| other.last.res.present_items().all(|b| a.krate == b.krate)) + } + + /// Indicates this [`LintPoint`] should be emitted to the user. + fn should_emit(&self, cx: &LateContext<'_>, msrv: Msrv) -> bool { + // NOTE: + // Consider using `self.first.span.can_be_used_for_suggestions()` + + !self.first.span.in_external_macro(cx.sess().source_map()) + && self + .last + .res + .present_items() + .all(|a| is_stable(cx, a, msrv) && self.first.res.krate != a.krate && self.defined_in() == a.krate) + } + + fn defined_in(&self) -> CrateNum { + self.last + .res + .present_items() + .next() + .expect("LintPoint only created if at least one Namespace resolved") + .krate + } + + fn merge_top(lint_points: &[Self], top: &ItemContext) -> Option { + lint_points + .iter() + .rev() + .take(top.lint_points) + .try_fold(Option::<&Self>::None, |a, b| match a { + Some(a) if a.compatible_with(b) => Some(Some(a)), + None => Some(Some(b)), + _ => None, + }) + .flatten() + .map(|representative| Self { + last: Path { + span: top.span, + ..representative.last + }, + ..*representative + }) + } +} + +#[derive(Debug)] +struct ItemContext { + span: Span, + lint_points: usize, +} + +#[derive(Clone, Copy, Debug, Default)] +struct CrateContext { + core: Option, + alloc: Option, +} + +/// Indicates a crate is marked as `#![no_core]` or `#![no_implicit_prelude]`, +/// both of which cause `core` to not be implicitly available. +pub fn no_implicit_core(cx: &LateContext<'_>) -> bool { + find_attr!(cx.tcx, crate, NoCore | NoImplicitPrelude) +} diff --git a/tests/ui/std_instead_of_core.fixed b/tests/ui/std_instead_of_core.fixed index 63d0e204d72f..5be46c89d21b 100644 --- a/tests/ui/std_instead_of_core.fixed +++ b/tests/ui/std_instead_of_core.fixed @@ -89,13 +89,6 @@ fn msrv_1_76(_: std::net::IpAddr) {} fn msrv_1_77(_: core::net::IpAddr) {} //~^ std_instead_of_core -#[warn(clippy::alloc_instead_of_core)] -fn issue15579() { - use std::alloc; - - let layout = alloc::Layout::new::(); -} - #[warn(clippy::std_instead_of_core)] fn issue13158_core_io() { // items moved from std::io into core::io are stable in an unstable module. @@ -115,3 +108,26 @@ fn issue13158_msrv_1_80(_: &dyn std::error::Error) {} #[clippy::msrv = "1.81"] fn issue13158_msrv_1_81(_: &dyn core::error::Error) {} //~^ std_instead_of_core + +#[warn(clippy::std_instead_of_core)] +fn issue17260() { + use core::concat; + //~^ std_instead_of_core +} + +#[warn(clippy::std_instead_of_alloc)] +fn non_use_paths() { + type Foo = alloc::sync::Arc>; + //~^ std_instead_of_alloc + + let _x = core::iter::repeat(u8::default()); + //~^ std_instead_of_core + + fn impl_trait(_: impl core::fmt::Display) {} + //~^ std_instead_of_core + + struct Bar { + layout: core::alloc::Layout, + //~^ std_instead_of_core + } +} diff --git a/tests/ui/std_instead_of_core.rs b/tests/ui/std_instead_of_core.rs index e5cde188bedd..54f727c9d9bc 100644 --- a/tests/ui/std_instead_of_core.rs +++ b/tests/ui/std_instead_of_core.rs @@ -89,13 +89,6 @@ fn msrv_1_76(_: std::net::IpAddr) {} fn msrv_1_77(_: std::net::IpAddr) {} //~^ std_instead_of_core -#[warn(clippy::alloc_instead_of_core)] -fn issue15579() { - use std::alloc; - - let layout = alloc::Layout::new::(); -} - #[warn(clippy::std_instead_of_core)] fn issue13158_core_io() { // items moved from std::io into core::io are stable in an unstable module. @@ -115,3 +108,26 @@ fn issue13158_msrv_1_80(_: &dyn std::error::Error) {} #[clippy::msrv = "1.81"] fn issue13158_msrv_1_81(_: &dyn std::error::Error) {} //~^ std_instead_of_core + +#[warn(clippy::std_instead_of_core)] +fn issue17260() { + use std::concat; + //~^ std_instead_of_core +} + +#[warn(clippy::std_instead_of_alloc)] +fn non_use_paths() { + type Foo = std::sync::Arc>; + //~^ std_instead_of_alloc + + let _x = std::iter::repeat(u8::default()); + //~^ std_instead_of_core + + fn impl_trait(_: impl std::fmt::Display) {} + //~^ std_instead_of_core + + struct Bar { + layout: std::alloc::Layout, + //~^ std_instead_of_core + } +} diff --git a/tests/ui/std_instead_of_core.stderr b/tests/ui/std_instead_of_core.stderr index 7045d4448211..5082e68c1642 100644 --- a/tests/ui/std_instead_of_core.stderr +++ b/tests/ui/std_instead_of_core.stderr @@ -98,16 +98,46 @@ LL | fn msrv_1_77(_: std::net::IpAddr) {} | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:109:33 + --> tests/ui/std_instead_of_core.rs:102:33 | LL | fn issue13158_msrv_1_41(_: &dyn std::panic::UnwindSafe) {} | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` - --> tests/ui/std_instead_of_core.rs:116:33 + --> tests/ui/std_instead_of_core.rs:109:33 | LL | fn issue13158_msrv_1_81(_: &dyn std::error::Error) {} | ^^^ help: consider importing the item from `core`: `core` -error: aborting due to 17 previous errors +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core.rs:114:9 + | +LL | use std::concat; + | ^^^ help: consider importing the item from `core`: `core` + +error: used import from `std` instead of `alloc` + --> tests/ui/std_instead_of_core.rs:120:16 + | +LL | type Foo = std::sync::Arc>; + | ^^^ help: consider importing the item from `alloc`: `alloc` + +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core.rs:123:14 + | +LL | let _x = std::iter::repeat(u8::default()); + | ^^^ help: consider importing the item from `core`: `core` + +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core.rs:126:27 + | +LL | fn impl_trait(_: impl std::fmt::Display) {} + | ^^^ help: consider importing the item from `core`: `core` + +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core.rs:130:17 + | +LL | layout: std::alloc::Layout, + | ^^^ help: consider importing the item from `core`: `core` + +error: aborting due to 22 previous errors diff --git a/tests/ui/std_instead_of_core_local_alloc.fixed b/tests/ui/std_instead_of_core_local_alloc.fixed new file mode 100644 index 000000000000..2918edc288ef --- /dev/null +++ b/tests/ui/std_instead_of_core_local_alloc.fixed @@ -0,0 +1,37 @@ +#![warn(clippy::std_instead_of_alloc)] +#![allow(unused_imports)] + +#[rustfmt::skip] +fn issue16695() { + extern crate alloc; + + use alloc::collections::VecDeque; + //~^ std_instead_of_alloc + + { + use alloc::vec::Vec; + //~^ std_instead_of_alloc + } +} + +mod a { + extern crate alloc as alloc_a; + + fn b() { + mod c { + extern crate alloc as alloc_b; + + fn d() { + fn e() { + // This should suggest alloc_b + use alloc_b::vec::Vec; + //~^ std_instead_of_alloc + } + } + } + } + + // This should suggest alloc_a + use alloc_a::vec::Vec; + //~^ std_instead_of_alloc +} diff --git a/tests/ui/std_instead_of_core_local_alloc.rs b/tests/ui/std_instead_of_core_local_alloc.rs new file mode 100644 index 000000000000..e90404c69f22 --- /dev/null +++ b/tests/ui/std_instead_of_core_local_alloc.rs @@ -0,0 +1,37 @@ +#![warn(clippy::std_instead_of_alloc)] +#![allow(unused_imports)] + +#[rustfmt::skip] +fn issue16695() { + extern crate alloc; + + use std::collections::VecDeque; + //~^ std_instead_of_alloc + + { + use std::vec::Vec; + //~^ std_instead_of_alloc + } +} + +mod a { + extern crate alloc as alloc_a; + + fn b() { + mod c { + extern crate alloc as alloc_b; + + fn d() { + fn e() { + // This should suggest alloc_b + use std::vec::Vec; + //~^ std_instead_of_alloc + } + } + } + } + + // This should suggest alloc_a + use std::vec::Vec; + //~^ std_instead_of_alloc +} diff --git a/tests/ui/std_instead_of_core_local_alloc.stderr b/tests/ui/std_instead_of_core_local_alloc.stderr new file mode 100644 index 000000000000..9ee13b45384a --- /dev/null +++ b/tests/ui/std_instead_of_core_local_alloc.stderr @@ -0,0 +1,29 @@ +error: used import from `std` instead of `alloc` + --> tests/ui/std_instead_of_core_local_alloc.rs:8:9 + | +LL | use std::collections::VecDeque; + | ^^^ help: consider importing the item from `alloc`: `alloc` + | + = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]` + +error: used import from `std` instead of `alloc` + --> tests/ui/std_instead_of_core_local_alloc.rs:12:13 + | +LL | use std::vec::Vec; + | ^^^ help: consider importing the item from `alloc`: `alloc` + +error: used import from `std` instead of `alloc` + --> tests/ui/std_instead_of_core_local_alloc.rs:27:25 + | +LL | use std::vec::Vec; + | ^^^ help: consider importing the item from `alloc`: `alloc_b` + +error: used import from `std` instead of `alloc` + --> tests/ui/std_instead_of_core_local_alloc.rs:35:9 + | +LL | use std::vec::Vec; + | ^^^ help: consider importing the item from `alloc`: `alloc_a` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/std_instead_of_core_unfixable.rs b/tests/ui/std_instead_of_core_unfixable.rs index 459db5e8944a..da2ea94635cd 100644 --- a/tests/ui/std_instead_of_core_unfixable.rs +++ b/tests/ui/std_instead_of_core_unfixable.rs @@ -23,3 +23,100 @@ fn pr16964() { ffi::OsString, }; } + +#[warn(clippy::alloc_instead_of_core)] +fn issue15579() { + use std::alloc; + + let layout = alloc::Layout::new::(); + //~^ std_instead_of_core +} + +#[rustfmt::skip] +fn issue12468() { + use std::{ + fmt::Result, + //~^ std_instead_of_core + io::Write, + }; + + use std::sync::{ + Arc, + //~^ std_instead_of_alloc + Mutex, + }; +} + +#[allow(clippy::legacy_numeric_constants)] +#[warn(clippy::alloc_instead_of_core)] +#[rustfmt::skip] +fn pr17252_large() { + extern crate alloc; + + use { + std::sync::Mutex, + ::{ + std::{ + fmt::{*, Formatter}, + //~^ std_instead_of_alloc + //~| std_instead_of_core + fs, + //~v std_instead_of_core + sync::atomic, + //~v std_instead_of_core + sync::atomic::{ + AtomicUsize, + AtomicU8, + Ordering, + }, + }, + core::u32, + std::collections::HashMap, + }, + alloc::{ + fmt::Result as FmtResult, + //~^ alloc_instead_of_core + format, + } + }; +} + +#[warn(clippy::alloc_instead_of_core)] +#[rustfmt::skip] +fn issue11159() { + use std::fmt; + //~^ std_instead_of_alloc + + struct S; + + impl fmt::Display for S { + //~^ alloc_instead_of_core + fn fmt( + &self, + _: &mut fmt::Formatter<'_>, + //~^ alloc_instead_of_core + ) -> fmt::Result { + //~^ alloc_instead_of_core + todo!() + } + } +} + +#[warn(clippy::alloc_instead_of_core)] +#[rustfmt::skip] +fn mixed_name_spaces() { + extern crate alloc; + + use std::{ + io, + iter::repeat_with, + //~^ std_instead_of_core + }; + + use alloc::alloc::{ + alloc, + dealloc, + Layout, + //~^ alloc_instead_of_core + }; +} diff --git a/tests/ui/std_instead_of_core_unfixable.stderr b/tests/ui/std_instead_of_core_unfixable.stderr index c79b3e48cad3..910ac179f001 100644 --- a/tests/ui/std_instead_of_core_unfixable.stderr +++ b/tests/ui/std_instead_of_core_unfixable.stderr @@ -42,5 +42,124 @@ LL | collections::BTreeSet, | = help: consider importing the item from `alloc` -error: aborting due to 5 previous errors +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core_unfixable.rs:31:18 + | +LL | let layout = alloc::Layout::new::(); + | ^^^^^^^^^^^^^ + | + = help: consider importing the item from `core` + +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core_unfixable.rs:38:14 + | +LL | fmt::Result, + | ^^^^^^ + | + = help: consider importing the item from `core` + +error: used import from `std` instead of `alloc` + --> tests/ui/std_instead_of_core_unfixable.rs:44:9 + | +LL | Arc, + | ^^^ + | + = help: consider importing the item from `alloc` + +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core_unfixable.rs:60:26 + | +LL | fmt::{*, Formatter}, + | ^^^^^^^^^ + | + = help: consider importing the item from `core` + +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core_unfixable.rs:65:23 + | +LL | sync::atomic, + | ^^^^^^ + | + = help: consider importing the item from `core` + +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core_unfixable.rs:67:17 + | +LL | / sync::atomic::{ +LL | | AtomicUsize, +LL | | AtomicU8, +LL | | Ordering, +LL | | }, + | |_________________^ + | + = help: consider importing the item from `core` + +error: used import from `std` instead of `alloc` + --> tests/ui/std_instead_of_core_unfixable.rs:60:17 + | +LL | fmt::{*, Formatter}, + | ^^^ + | + = help: consider importing the item from `alloc` + +error: used import from `alloc` instead of `core` + --> tests/ui/std_instead_of_core_unfixable.rs:77:18 + | +LL | fmt::Result as FmtResult, + | ^^^^^^ + | + = help: consider importing the item from `core` + = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::alloc_instead_of_core)]` + +error: used import from `std` instead of `alloc` + --> tests/ui/std_instead_of_core_unfixable.rs:87:9 + | +LL | use std::fmt; + | ^^^ + | + = help: consider importing the item from `alloc` + = help: consider adding an `extern crate` statement at the crate root + +error: used import from `alloc` instead of `core` + --> tests/ui/std_instead_of_core_unfixable.rs:92:10 + | +LL | impl fmt::Display for S { + | ^^^^^^^^^^^^ + | + = help: consider importing the item from `core` + +error: used import from `alloc` instead of `core` + --> tests/ui/std_instead_of_core_unfixable.rs:96:21 + | +LL | _: &mut fmt::Formatter<'_>, + | ^^^^^^^^^^^^^^ + | + = help: consider importing the item from `core` + +error: used import from `alloc` instead of `core` + --> tests/ui/std_instead_of_core_unfixable.rs:98:14 + | +LL | ) -> fmt::Result { + | ^^^^^^^^^^^ + | + = help: consider importing the item from `core` + +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core_unfixable.rs:112:15 + | +LL | iter::repeat_with, + | ^^^^^^^^^^^ + | + = help: consider importing the item from `core` + +error: used import from `alloc` instead of `core` + --> tests/ui/std_instead_of_core_unfixable.rs:119:9 + | +LL | Layout, + | ^^^^^^ + | + = help: consider importing the item from `core` + +error: aborting due to 19 previous errors diff --git a/tests/ui/std_instead_of_core_unfixable_no_alloc.rs b/tests/ui/std_instead_of_core_unfixable_no_alloc.rs new file mode 100644 index 000000000000..028b967e9705 --- /dev/null +++ b/tests/ui/std_instead_of_core_unfixable_no_alloc.rs @@ -0,0 +1,12 @@ +#![warn(clippy::std_instead_of_alloc)] +#![allow(unused_imports)] + +const _: () = { + extern crate alloc; +}; + +#[rustfmt::skip] +fn issue16695() { + use std::collections::VecDeque; + //~^ std_instead_of_alloc +} diff --git a/tests/ui/std_instead_of_core_unfixable_no_alloc.stderr b/tests/ui/std_instead_of_core_unfixable_no_alloc.stderr new file mode 100644 index 000000000000..b707d0f3d4db --- /dev/null +++ b/tests/ui/std_instead_of_core_unfixable_no_alloc.stderr @@ -0,0 +1,13 @@ +error: used import from `std` instead of `alloc` + --> tests/ui/std_instead_of_core_unfixable_no_alloc.rs:10:9 + | +LL | use std::collections::VecDeque; + | ^^^ + | + = help: consider importing the item from `alloc` + = help: consider adding an `extern crate` statement at the crate root + = note: `-D clippy::std-instead-of-alloc` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]` + +error: aborting due to 1 previous error + diff --git a/tests/ui/std_instead_of_core_unfixable_no_core.rs b/tests/ui/std_instead_of_core_unfixable_no_core.rs new file mode 100644 index 000000000000..9a540bf7af48 --- /dev/null +++ b/tests/ui/std_instead_of_core_unfixable_no_core.rs @@ -0,0 +1,18 @@ +#![warn(clippy::std_instead_of_core)] +#![allow(unused_imports)] +#![no_implicit_prelude] + +const _: () = { + extern crate core; +}; + +extern crate std; + +fn issue15836() { + use std::cmp::{self, Eq, Ordering, PartialEq, PartialOrd}; + //~^ std_instead_of_core + use std::option::Option::{self, Some}; + //~^ std_instead_of_core + use std::todo; + //~^ std_instead_of_core +} diff --git a/tests/ui/std_instead_of_core_unfixable_no_core.stderr b/tests/ui/std_instead_of_core_unfixable_no_core.stderr new file mode 100644 index 000000000000..5a4325b45baf --- /dev/null +++ b/tests/ui/std_instead_of_core_unfixable_no_core.stderr @@ -0,0 +1,31 @@ +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core_unfixable_no_core.rs:12:9 + | +LL | use std::cmp::{self, Eq, Ordering, PartialEq, PartialOrd}; + | ^^^ + | + = help: consider importing the item from `core` + = help: consider adding an `extern crate` statement at the crate root + = note: `-D clippy::std-instead-of-core` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::std_instead_of_core)]` + +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core_unfixable_no_core.rs:14:9 + | +LL | use std::option::Option::{self, Some}; + | ^^^ + | + = help: consider importing the item from `core` + = help: consider adding an `extern crate` statement at the crate root + +error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core_unfixable_no_core.rs:16:9 + | +LL | use std::todo; + | ^^^ + | + = help: consider importing the item from `core` + = help: consider adding an `extern crate` statement at the crate root + +error: aborting due to 3 previous errors +