incompatible_msrv: Don't check the contents of any std macro.
This commit is contained in:
parent
ee4390f070
commit
a537e86e7f
3 changed files with 54 additions and 21 deletions
|
|
@ -1,14 +1,14 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::msrvs::Msrv;
|
||||
use clippy_utils::{is_in_const_context, is_in_test};
|
||||
use clippy_utils::{is_in_const_context, is_in_test, sym};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, HirId, RustcVersion, StabilityLevel, StableSince};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::def_id::{CrateNum, DefId};
|
||||
use rustc_span::{ExpnKind, Span, sym};
|
||||
use rustc_span::{ExpnKind, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -77,11 +77,36 @@ enum Availability {
|
|||
Since(RustcVersion),
|
||||
}
|
||||
|
||||
/// All known std crates containing a stability attribute.
|
||||
struct StdCrates([Option<CrateNum>; 6]);
|
||||
impl StdCrates {
|
||||
fn new(tcx: TyCtxt<'_>) -> Self {
|
||||
let mut res = Self([None; _]);
|
||||
for &krate in tcx.crates(()) {
|
||||
// FIXME(@Jarcho): We should have an internal lint to detect when this list is out of date.
|
||||
match tcx.crate_name(krate) {
|
||||
sym::alloc => res.0[0] = Some(krate),
|
||||
sym::core => res.0[1] = Some(krate),
|
||||
sym::core_arch => res.0[2] = Some(krate),
|
||||
sym::proc_macro => res.0[3] = Some(krate),
|
||||
sym::std => res.0[4] = Some(krate),
|
||||
sym::std_detect => res.0[5] = Some(krate),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn contains(&self, krate: CrateNum) -> bool {
|
||||
self.0.contains(&Some(krate))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IncompatibleMsrv {
|
||||
msrv: Msrv,
|
||||
availability_cache: FxHashMap<(DefId, bool), Availability>,
|
||||
check_in_tests: bool,
|
||||
core_crate: Option<CrateNum>,
|
||||
std_crates: StdCrates,
|
||||
|
||||
// The most recently called path. Used to skip checking the path after it's
|
||||
// been checked when visiting the call expression.
|
||||
|
|
@ -96,11 +121,7 @@ impl IncompatibleMsrv {
|
|||
msrv: conf.msrv,
|
||||
availability_cache: FxHashMap::default(),
|
||||
check_in_tests: conf.check_incompatible_msrv_in_tests,
|
||||
core_crate: tcx
|
||||
.crates(())
|
||||
.iter()
|
||||
.find(|krate| tcx.crate_name(**krate) == sym::core)
|
||||
.copied(),
|
||||
std_crates: StdCrates::new(tcx),
|
||||
called_path: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -152,21 +173,24 @@ impl IncompatibleMsrv {
|
|||
node: HirId,
|
||||
span: Span,
|
||||
) {
|
||||
if def_id.is_local() {
|
||||
// We don't check local items since their MSRV is supposed to always be valid.
|
||||
if !self.std_crates.contains(def_id.krate) {
|
||||
// No stability attributes to lookup for these items.
|
||||
return;
|
||||
}
|
||||
let expn_data = span.ctxt().outer_expn_data();
|
||||
if let ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) = expn_data.kind {
|
||||
// Desugared expressions get to cheat and stability is ignored.
|
||||
// Intentionally not using `.from_expansion()`, since we do still care about macro expansions
|
||||
return;
|
||||
}
|
||||
// Functions coming from `core` while expanding a macro such as `assert*!()` get to cheat too: the
|
||||
// macros may have existed prior to the checked MSRV, but their expansion with a recent compiler
|
||||
// might use recent functions or methods. Compiling with an older compiler would not use those.
|
||||
if Some(def_id.krate) == self.core_crate && expn_data.macro_def_id.map(|did| did.krate) == self.core_crate {
|
||||
return;
|
||||
// Use `from_expansion` to fast-path the common case.
|
||||
if span.from_expansion() {
|
||||
let expn = span.ctxt().outer_expn_data();
|
||||
match expn.kind {
|
||||
// FIXME(@Jarcho): Check that the actual desugaring or std macro is supported by the
|
||||
// current MSRV. Note that nested expansions need to be handled as well.
|
||||
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => return,
|
||||
ExpnKind::Macro(..) if expn.macro_def_id.is_some_and(|did| self.std_crates.contains(did.krate)) => {
|
||||
return;
|
||||
},
|
||||
// All other expansions share the target's MSRV.
|
||||
// FIXME(@Jarcho): What should we do about version dependant macros from external crates?
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
if (self.check_in_tests || !is_in_test(cx.tcx, node))
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ generate! {
|
|||
copy_from_nonoverlapping,
|
||||
copy_to,
|
||||
copy_to_nonoverlapping,
|
||||
core_arch,
|
||||
count_ones,
|
||||
create,
|
||||
create_new,
|
||||
|
|
@ -331,6 +332,7 @@ generate! {
|
|||
splitn_mut,
|
||||
sqrt,
|
||||
starts_with,
|
||||
std_detect,
|
||||
step_by,
|
||||
strlen,
|
||||
style,
|
||||
|
|
|
|||
|
|
@ -178,4 +178,11 @@ const fn uncalled_len() {
|
|||
//~^ incompatible_msrv
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.0.0"]
|
||||
fn vec_macro() {
|
||||
let _: Vec<u32> = vec![];
|
||||
let _: Vec<u32> = vec![1; 3];
|
||||
let _: Vec<u32> = vec![1, 2];
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue