Skip to content

Commit 2ea0126

Browse files
authored
Rollup merge of rust-lang#104006 - flip1995:lang-items-clippy, r=oli-obk
Add variant_name function to `LangItem` Clippy has an internal lint that checks for the usage of hardcoded def paths and suggests to replace them with a lang or diagnostic item, if possible. This was implemented with a hack, by getting all the variants of the `LangItem` enum and then index into it with the position of the `LangItem` in the `items` list. This is no longer possible, because the `items` list can't be accessed anymore. Follow up to rust-lang#103603 cc `@camsteffen` r? `@oli-obk` This is blocking the sync between Clippy and Rust. I'm not sure if this is the best solution here, or if I should add a method `items()` to `LanguageItems` and keep the code in Clippy unchanged.
2 parents 6419151 + 4e65f5e commit 2ea0126

File tree

6 files changed

+35
-36
lines changed

6 files changed

+35
-36
lines changed

compiler/rustc_hir/src/lang_items.rs

+8
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ macro_rules! language_item_table {
9595
}
9696
}
9797

98+
/// Returns the name of the `LangItem` enum variant.
99+
// This method is used by Clippy for internal lints.
100+
pub fn variant_name(self) -> &'static str {
101+
match self {
102+
$( LangItem::$variant => stringify!($variant), )*
103+
}
104+
}
105+
98106
pub fn target(self) -> Target {
99107
match self {
100108
$( LangItem::$variant => $target, )*

src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -79,22 +79,22 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
7979
SimplifiedTypeGen::StrSimplifiedType,
8080
]
8181
.iter()
82-
.flat_map(|&ty| cx.tcx.incoherent_impls(ty));
83-
for item_def_id in lang_items.items().iter().flatten().chain(incoherent_impls) {
84-
let lang_item_path = cx.get_def_path(*item_def_id);
82+
.flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter().copied());
83+
for item_def_id in lang_items.iter().map(|(_, def_id)| def_id).chain(incoherent_impls) {
84+
let lang_item_path = cx.get_def_path(item_def_id);
8585
if path_syms.starts_with(&lang_item_path) {
8686
if let [item] = &path_syms[lang_item_path.len()..] {
8787
if matches!(
88-
cx.tcx.def_kind(*item_def_id),
88+
cx.tcx.def_kind(item_def_id),
8989
DefKind::Mod | DefKind::Enum | DefKind::Trait
9090
) {
91-
for child in cx.tcx.module_children(*item_def_id) {
91+
for child in cx.tcx.module_children(item_def_id) {
9292
if child.ident.name == *item {
9393
return true;
9494
}
9595
}
9696
} else {
97-
for child in cx.tcx.associated_item_def_ids(*item_def_id) {
97+
for child in cx.tcx.associated_item_def_ids(item_def_id) {
9898
if cx.tcx.item_name(*child) == *item {
9999
return true;
100100
}

src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs

+5-14
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_ast::ast::LitKind;
66
use rustc_data_structures::fx::FxHashSet;
77
use rustc_errors::Applicability;
88
use rustc_hir as hir;
9-
use rustc_hir::def::{DefKind, Namespace, Res};
9+
use rustc_hir::def::{DefKind, Res};
1010
use rustc_hir::def_id::DefId;
1111
use rustc_hir::{Expr, ExprKind, Local, Mutability, Node};
1212
use rustc_lint::{LateContext, LateLintPass};
@@ -91,7 +91,7 @@ impl UnnecessaryDefPath {
9191
#[allow(clippy::too_many_lines)]
9292
fn check_call(&mut self, cx: &LateContext<'_>, func: &Expr<'_>, args: &[Expr<'_>], span: Span) {
9393
enum Item {
94-
LangItem(Symbol),
94+
LangItem(&'static str),
9595
DiagnosticItem(Symbol),
9696
}
9797
static PATHS: &[&[&str]] = &[
@@ -325,18 +325,9 @@ fn inherent_def_path_res(cx: &LateContext<'_>, segments: &[&str]) -> Option<DefI
325325
})
326326
}
327327

328-
fn get_lang_item_name(cx: &LateContext<'_>, def_id: DefId) -> Option<Symbol> {
329-
if let Some(lang_item) = cx.tcx.lang_items().items().iter().position(|id| *id == Some(def_id)) {
330-
let lang_items = def_path_res(cx, &["rustc_hir", "lang_items", "LangItem"], Some(Namespace::TypeNS)).def_id();
331-
let item_name = cx
332-
.tcx
333-
.adt_def(lang_items)
334-
.variants()
335-
.iter()
336-
.nth(lang_item)
337-
.unwrap()
338-
.name;
339-
Some(item_name)
328+
fn get_lang_item_name(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static str> {
329+
if let Some((lang_item, _)) = cx.tcx.lang_items().iter().find(|(_, id)| *id == def_id) {
330+
Some(lang_item.variant_name())
340331
} else {
341332
None
342333
}

src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed

+3-3
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) {
4848
let _ = is_type_lang_item(cx, ty, LangItem::OwnedBox);
4949
let _ = is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit);
5050

51-
let _ = cx.tcx.lang_items().require(LangItem::OwnedBox).ok() == Some(did);
51+
let _ = cx.tcx.lang_items().get(LangItem::OwnedBox) == Some(did);
5252
let _ = cx.tcx.is_diagnostic_item(sym::Option, did);
53-
let _ = cx.tcx.lang_items().require(LangItem::OptionSome).ok() == Some(did);
53+
let _ = cx.tcx.lang_items().get(LangItem::OptionSome) == Some(did);
5454

5555
let _ = is_trait_method(cx, expr, sym::AsRef);
5656

5757
let _ = is_path_diagnostic_item(cx, expr, sym::Option);
58-
let _ = path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().require(LangItem::IteratorNext).ok() == Some(id));
58+
let _ = path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().get(LangItem::IteratorNext) == Some(id));
5959
let _ = is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome);
6060
}
6161

src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ error: use of a def path to a `LangItem`
5757
--> $DIR/unnecessary_def_path.rs:51:13
5858
|
5959
LL | let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]);
60-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().require(LangItem::OwnedBox).ok() == Some(did)`
60+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OwnedBox) == Some(did)`
6161

6262
error: use of a def path to a diagnostic item
6363
--> $DIR/unnecessary_def_path.rs:52:13
@@ -69,7 +69,7 @@ error: use of a def path to a `LangItem`
6969
--> $DIR/unnecessary_def_path.rs:53:13
7070
|
7171
LL | let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]);
72-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().require(LangItem::OptionSome).ok() == Some(did)`
72+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OptionSome) == Some(did)`
7373
|
7474
= help: if this `DefId` came from a constructor expression or pattern then the parent `DefId` should be used instead
7575

@@ -89,7 +89,7 @@ error: use of a def path to a `LangItem`
8989
--> $DIR/unnecessary_def_path.rs:58:13
9090
|
9191
LL | let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]);
92-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().require(LangItem::IteratorNext).ok() == Some(id))`
92+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().get(LangItem::IteratorNext) == Some(id))`
9393

9494
error: use of a def path to a `LangItem`
9595
--> $DIR/unnecessary_def_path.rs:59:13
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error: hardcoded path to a language item
2-
--> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
1+
error: hardcoded path to a diagnostic item
2+
--> $DIR/unnecessary_def_path_hardcoded_path.rs:10:36
33
|
4-
LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4+
LL | const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= help: convert all references to use `LangItem::DerefMut`
7+
= help: convert all references to use `sym::Deref`
88
= note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
99

1010
error: hardcoded path to a diagnostic item
@@ -15,13 +15,13 @@ LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref",
1515
|
1616
= help: convert all references to use `sym::deref_method`
1717

18-
error: hardcoded path to a diagnostic item
19-
--> $DIR/unnecessary_def_path_hardcoded_path.rs:10:36
18+
error: hardcoded path to a language item
19+
--> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
2020
|
21-
LL | const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
22-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
21+
LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2323
|
24-
= help: convert all references to use `sym::Deref`
24+
= help: convert all references to use `LangItem::DerefMut`
2525

2626
error: aborting due to 3 previous errors
2727

0 commit comments

Comments
 (0)