1- use clippy_utils:: { diagnostics:: span_lint_and_sugg, source:: snippet, ty :: ty_from_hir_ty } ;
1+ use clippy_utils:: { diagnostics:: span_lint_and_sugg, source:: snippet} ;
22use rustc_errors:: Applicability ;
3- use rustc_hir:: { QPath , TyKind } ;
3+ use rustc_hir:: {
4+ HirId , Path , PathSegment ,
5+ def:: { DefKind , Res } ,
6+ } ;
47use rustc_lint:: { LateContext , LateLintPass } ;
58
6- use crate :: { declare_bevy_lint, declare_bevy_lint_pass} ;
9+ use crate :: { declare_bevy_lint, declare_bevy_lint_pass, sym } ;
710
811declare_bevy_lint ! {
912 pub ( crate ) BEVY_PLATFORM_ALTERNATIVE_EXISTS ,
@@ -16,48 +19,56 @@ declare_bevy_lint_pass! {
1619}
1720
1821impl < ' tcx > LateLintPass < ' tcx > for BevyPlatformAlternativeExists {
19- fn check_ty (
20- & mut self ,
21- cx : & LateContext < ' tcx > ,
22- hir_ty : & ' tcx rustc_hir:: Ty < ' tcx , rustc_hir:: AmbigArg > ,
23- ) {
24- if hir_ty. span . in_external_macro ( cx. tcx . sess . source_map ( ) ) {
25- return ;
26- }
27-
28- let as_unambig_ty = hir_ty. as_unambig_ty ( ) ;
29-
30- // lower the [`hir::Ty`] to a [`rustc_middle::ty::Ty`]
31- let ty = ty_from_hir_ty ( cx, as_unambig_ty) ;
32-
33- // Get the path to the type definition.
34- let TyKind :: Path ( QPath :: Resolved ( _, path) ) = & as_unambig_ty. kind else {
35- return ;
36- } ;
37-
38- // if for the given `ty` an alternative from `bevy_platform` exists.
39- if let Some ( bevy_platform_alternative) = BevyPlatformType :: try_from_ty ( cx, ty)
40- // Only emit a lint if the first segment of this path is `std` thus the type originates
41- // from the standart library. This prevents linting for `bevy::platform` types that are just a reexport of the `std`.
42- && path. segments . first ( ) . is_some_and ( |segment| segment. ident . name . as_str ( ) . starts_with ( "std" ) )
22+ fn check_path ( & mut self , cx : & LateContext < ' tcx > , path : & Path < ' tcx > , _: HirId ) {
23+ // Skip if this path is from an external macro.
24+ if !path. span . in_external_macro ( cx. tcx . sess . source_map ( ) )
25+ // Retrieve the first path segment.
26+ && let Some ( first_segment) = get_first_segment ( path)
27+ // Check that the crate root is `std`.
28+ && first_segment. ident . name == sym:: std
29+ // Get the def_id of the crate from first segment.
30+ && let Res :: Def ( DefKind :: Mod , crate_def_id) = first_segment. res
31+ // If the first segment is not the crate root, then this type was checked when
32+ // importing.
33+ && crate_def_id. is_crate_root ( )
34+ // Get the `PathSegment` that corresponds to the type we want to check against.
35+ && let Some ( last_segment) = path. segments . last ( )
36+ && let Res :: Def ( _, last_segment_def_id) = last_segment. res
4337 {
44- span_lint_and_sugg (
45- cx,
46- BEVY_PLATFORM_ALTERNATIVE_EXISTS ,
47- hir_ty. span ,
48- BEVY_PLATFORM_ALTERNATIVE_EXISTS . desc ,
49- format ! (
50- "the type `{}` can be replaced with the `no_std` compatible type {}" ,
51- snippet( cx. tcx. sess, hir_ty. span, "" ) ,
52- bevy_platform_alternative. full_path( )
53- ) ,
54- bevy_platform_alternative. full_path ( ) . to_string ( ) ,
55- Applicability :: MachineApplicable ,
56- ) ;
38+ let ty = cx. tcx . type_of ( last_segment_def_id) . skip_binder ( ) ;
39+ if let Some ( bevy_platform_alternative) = BevyPlatformType :: try_from_ty ( cx, ty) {
40+ span_lint_and_sugg (
41+ cx,
42+ BEVY_PLATFORM_ALTERNATIVE_EXISTS ,
43+ path. span ,
44+ BEVY_PLATFORM_ALTERNATIVE_EXISTS . desc ,
45+ format ! (
46+ "the type `{}` can be replaced with the `no_std` compatible type {}" ,
47+ snippet( cx. tcx. sess, path. span, "" ) ,
48+ bevy_platform_alternative. full_path( )
49+ ) ,
50+ bevy_platform_alternative. full_path ( ) . to_string ( ) ,
51+ Applicability :: MachineApplicable ,
52+ ) ;
53+ }
5754 }
5855 }
5956}
6057
58+ /// Returns the first named segment of a [`Path`].
59+ ///
60+ /// If this is a global path (such as `::std::fmt::Debug`), then the segment after [`kw::PathRoot`]
61+ /// is returned.
62+ fn get_first_segment < ' tcx > ( path : & Path < ' tcx > ) -> Option < & ' tcx PathSegment < ' tcx > > {
63+ match path. segments {
64+ // A global path will have PathRoot as the first segment. In this case, return the segment
65+ // after.
66+ [ x, y, ..] if x. ident . name == rustc_span:: symbol:: kw:: PathRoot => Some ( y) ,
67+ [ x, ..] => Some ( x) ,
68+ _ => None ,
69+ }
70+ }
71+
6172/// Creates an enum containing all the types form `bevy_platform` as variants.
6273///
6374/// # Example
0 commit comments