@@ -2,7 +2,7 @@ use clippy_config::Conf;
22use clippy_utils:: diagnostics:: span_lint_and_then;
33use clippy_utils:: is_in_test;
44use clippy_utils:: msrvs:: Msrv ;
5- use rustc_attr_data_structures:: { RustcVersion , StabilityLevel , StableSince } ;
5+ use rustc_attr_data_structures:: { RustcVersion , Stability , StableSince } ;
66use rustc_data_structures:: fx:: FxHashMap ;
77use rustc_hir:: { Expr , ExprKind , HirId , QPath } ;
88use rustc_lint:: { LateContext , LateLintPass } ;
@@ -72,9 +72,15 @@ declare_clippy_lint! {
7272 "ensures that all items used in the crate are available for the current MSRV"
7373}
7474
75+ #[ derive( Clone , Copy ) ]
76+ enum Availability {
77+ FeatureEnabled ,
78+ Since ( RustcVersion ) ,
79+ }
80+
7581pub struct IncompatibleMsrv {
7682 msrv : Msrv ,
77- is_above_msrv : FxHashMap < DefId , RustcVersion > ,
83+ availability_cache : FxHashMap < DefId , Availability > ,
7884 check_in_tests : bool ,
7985}
8086
@@ -84,35 +90,32 @@ impl IncompatibleMsrv {
8490 pub fn new ( conf : & ' static Conf ) -> Self {
8591 Self {
8692 msrv : conf. msrv ,
87- is_above_msrv : FxHashMap :: default ( ) ,
93+ availability_cache : FxHashMap :: default ( ) ,
8894 check_in_tests : conf. check_incompatible_msrv_in_tests ,
8995 }
9096 }
9197
92- fn get_def_id_version ( & mut self , tcx : TyCtxt < ' _ > , def_id : DefId ) -> RustcVersion {
93- if let Some ( version) = self . is_above_msrv . get ( & def_id) {
94- return * version;
98+ /// Returns the availability of `def_id`, whether it is enabled through a feature or
99+ /// available since a given version (the default being Rust 1.0.0).
100+ fn get_def_id_availability ( & mut self , tcx : TyCtxt < ' _ > , def_id : DefId ) -> Availability {
101+ if let Some ( availability) = self . availability_cache . get ( & def_id) {
102+ return * availability;
95103 }
96- let version = if let Some ( version) = tcx
97- . lookup_stability ( def_id)
98- . and_then ( |stability| match stability. level {
99- StabilityLevel :: Stable {
100- since : StableSince :: Version ( version) ,
101- ..
102- } => Some ( version) ,
103- _ => None ,
104- } ) {
105- version
104+ let stability = tcx. lookup_stability ( def_id) ;
105+ let version = if stability. is_some_and ( |stability| tcx. features ( ) . enabled ( stability. feature ) ) {
106+ Availability :: FeatureEnabled
107+ } else if let Some ( StableSince :: Version ( version) ) = stability. as_ref ( ) . and_then ( Stability :: stable_since) {
108+ Availability :: Since ( version)
106109 } else if let Some ( parent_def_id) = tcx. opt_parent ( def_id) {
107- self . get_def_id_version ( tcx, parent_def_id)
110+ self . get_def_id_availability ( tcx, parent_def_id)
108111 } else {
109- RustcVersion {
112+ Availability :: Since ( RustcVersion {
110113 major : 1 ,
111114 minor : 0 ,
112115 patch : 0 ,
113- }
116+ } )
114117 } ;
115- self . is_above_msrv . insert ( def_id, version) ;
118+ self . availability_cache . insert ( def_id, version) ;
116119 version
117120 }
118121
@@ -143,7 +146,7 @@ impl IncompatibleMsrv {
143146
144147 if ( self . check_in_tests || !is_in_test ( cx. tcx , node) )
145148 && let Some ( current) = self . msrv . current ( cx)
146- && let version = self . get_def_id_version ( cx. tcx , def_id)
149+ && let Availability :: Since ( version) = self . get_def_id_availability ( cx. tcx , def_id)
147150 && version > current
148151 {
149152 span_lint_and_then (
0 commit comments