Skip to content

Commit a25afec

Browse files
committed
feat: switch to check_path based on zulip feedback
1 parent eeb34dc commit a25afec

File tree

1 file changed

+51
-40
lines changed

1 file changed

+51
-40
lines changed

bevy_lint/src/lints/style/bevy_platform_alternative_exists.rs

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
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};
22
use rustc_errors::Applicability;
3-
use rustc_hir::{QPath, TyKind};
3+
use rustc_hir::{
4+
HirId, Path, PathSegment,
5+
def::{DefKind, Res},
6+
};
47
use 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

811
declare_bevy_lint! {
912
pub(crate) BEVY_PLATFORM_ALTERNATIVE_EXISTS,
@@ -16,48 +19,56 @@ declare_bevy_lint_pass! {
1619
}
1720

1821
impl<'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

Comments
 (0)