Skip to content

Commit 0157cc9

Browse files
committed
Auto merge of #89534 - camsteffen:diag-name, r=oli-obk
Introduce `tcx.get_diagnostic_name` Introduces a "reverse lookup" for diagnostic items. This is mainly intended for `@rust-lang/clippy` which often does a long series of `is_diagnostic_item` calls for the same `DefId`. r? `@oli-obk`
2 parents 680ff86 + a8d8bfd commit 0157cc9

File tree

15 files changed

+142
-146
lines changed

15 files changed

+142
-146
lines changed
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use crate::def_id::DefId;
2+
use rustc_data_structures::fx::FxHashMap;
3+
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
4+
use rustc_span::Symbol;
5+
6+
#[derive(Debug, Default)]
7+
pub struct DiagnosticItems {
8+
pub id_to_name: FxHashMap<DefId, Symbol>,
9+
pub name_to_id: FxHashMap<Symbol, DefId>,
10+
}
11+
12+
impl<CTX: crate::HashStableContext> HashStable<CTX> for DiagnosticItems {
13+
#[inline]
14+
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
15+
self.name_to_id.hash_stable(ctx, hasher);
16+
}
17+
}

compiler/rustc_hir/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ mod arena;
1818
pub mod def;
1919
pub mod def_path_hash_map;
2020
pub mod definitions;
21+
pub mod diagnostic_items;
2122
pub use rustc_span::def_id;
2223
mod hir;
2324
pub mod hir_id;

compiler/rustc_lint/src/builtin.rs

+13-15
Original file line numberDiff line numberDiff line change
@@ -2478,14 +2478,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
24782478
// Find calls to `mem::{uninitialized,zeroed}` methods.
24792479
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
24802480
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
2481-
2482-
if cx.tcx.is_diagnostic_item(sym::mem_zeroed, def_id) {
2483-
return Some(InitKind::Zeroed);
2484-
} else if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, def_id) {
2485-
return Some(InitKind::Uninit);
2486-
} else if cx.tcx.is_diagnostic_item(sym::transmute, def_id) && is_zero(&args[0])
2487-
{
2488-
return Some(InitKind::Zeroed);
2481+
match cx.tcx.get_diagnostic_name(def_id) {
2482+
Some(sym::mem_zeroed) => return Some(InitKind::Zeroed),
2483+
Some(sym::mem_uninitialized) => return Some(InitKind::Uninit),
2484+
Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed),
2485+
_ => {}
24892486
}
24902487
}
24912488
} else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
@@ -2497,11 +2494,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
24972494
if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind {
24982495
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
24992496
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
2500-
2501-
if cx.tcx.is_diagnostic_item(sym::maybe_uninit_zeroed, def_id) {
2502-
return Some(InitKind::Zeroed);
2503-
} else if cx.tcx.is_diagnostic_item(sym::maybe_uninit_uninit, def_id) {
2504-
return Some(InitKind::Uninit);
2497+
match cx.tcx.get_diagnostic_name(def_id) {
2498+
Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed),
2499+
Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit),
2500+
_ => {}
25052501
}
25062502
}
25072503
}
@@ -3091,8 +3087,10 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
30913087
rustc_hir::ExprKind::Call(ref path, _) => {
30923088
if let rustc_hir::ExprKind::Path(ref qpath) = path.kind {
30933089
if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
3094-
return cx.tcx.is_diagnostic_item(sym::ptr_null, def_id)
3095-
|| cx.tcx.is_diagnostic_item(sym::ptr_null_mut, def_id);
3090+
return matches!(
3091+
cx.tcx.get_diagnostic_name(def_id),
3092+
Some(sym::ptr_null | sym::ptr_null_mut)
3093+
);
30963094
}
30973095
}
30983096
}

compiler/rustc_lint/src/internal.rs

+16-15
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,10 @@ impl LateLintPass<'_> for DefaultHashTypes {
3333
// don't lint imports, only actual usages
3434
return;
3535
}
36-
let replace = if cx.tcx.is_diagnostic_item(sym::HashMap, def_id) {
37-
"FxHashMap"
38-
} else if cx.tcx.is_diagnostic_item(sym::HashSet, def_id) {
39-
"FxHashSet"
40-
} else {
41-
return;
36+
let replace = match cx.tcx.get_diagnostic_name(def_id) {
37+
Some(sym::HashMap) => "FxHashMap",
38+
Some(sym::HashSet) => "FxHashSet",
39+
_ => return,
4240
};
4341
cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| {
4442
let msg = format!(
@@ -174,26 +172,29 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
174172
if let TyKind::Path(qpath) = &ty.kind {
175173
if let QPath::Resolved(_, path) = qpath {
176174
match path.res {
177-
Res::Def(_, did) => {
178-
if cx.tcx.is_diagnostic_item(sym::Ty, did) {
179-
return Some(format!("Ty{}", gen_args(path.segments.last().unwrap())));
180-
} else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) {
181-
return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap())));
175+
Res::Def(_, def_id) => {
176+
if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id)
177+
{
178+
return Some(format!(
179+
"{}{}",
180+
name,
181+
gen_args(path.segments.last().unwrap())
182+
));
182183
}
183184
}
184185
// Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
185186
Res::SelfTy(None, Some((did, _))) => {
186187
if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
187-
if cx.tcx.is_diagnostic_item(sym::Ty, adt.did) {
188+
if let Some(name @ (sym::Ty | sym::TyCtxt)) =
189+
cx.tcx.get_diagnostic_name(adt.did)
190+
{
188191
// NOTE: This path is currently unreachable as `Ty<'tcx>` is
189192
// defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
190193
// is not actually allowed.
191194
//
192195
// I(@lcnr) still kept this branch in so we don't miss this
193196
// if we ever change it in the future.
194-
return Some(format!("Ty<{}>", substs[0]));
195-
} else if cx.tcx.is_diagnostic_item(sym::TyCtxt, adt.did) {
196-
return Some(format!("TyCtxt<{}>", substs[0]));
197+
return Some(format!("{}<{}>", name, substs[0]));
197198
}
198199
}
199200
}

compiler/rustc_lint/src/non_fmt_panic.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,10 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
5454
|| Some(def_id) == cx.tcx.lang_items().panic_str()
5555
{
5656
if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
57-
if cx.tcx.is_diagnostic_item(sym::std_panic_2015_macro, id)
58-
|| cx.tcx.is_diagnostic_item(sym::core_panic_2015_macro, id)
59-
{
57+
if matches!(
58+
cx.tcx.get_diagnostic_name(id),
59+
Some(sym::core_panic_2015_macro | sym::std_panic_2015_macro)
60+
) {
6061
check_panic(cx, f, arg);
6162
}
6263
}

compiler/rustc_lint/src/noop_method_call.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,10 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
5151
Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) {
5252
// Check that we're dealing with a trait method for one of the traits we care about.
5353
Some(trait_id)
54-
if [sym::Clone, sym::Deref, sym::Borrow]
55-
.iter()
56-
.any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) =>
54+
if matches!(
55+
cx.tcx.get_diagnostic_name(trait_id),
56+
Some(sym::Borrow | sym::Clone | sym::Deref)
57+
) =>
5758
{
5859
(trait_id, did)
5960
}

compiler/rustc_lint/src/types.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1541,8 +1541,7 @@ impl InvalidAtomicOrdering {
15411541
if let ExprKind::Call(ref func, ref args) = expr.kind;
15421542
if let ExprKind::Path(ref func_qpath) = func.kind;
15431543
if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
1544-
if cx.tcx.is_diagnostic_item(sym::fence, def_id) ||
1545-
cx.tcx.is_diagnostic_item(sym::compiler_fence, def_id);
1544+
if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence));
15461545
if let ExprKind::Path(ref ordering_qpath) = &args[0].kind;
15471546
if let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id();
15481547
if Self::matches_ordering(cx, ordering_def_id, &[sym::Relaxed]);

compiler/rustc_metadata/src/rmeta/decoder.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc_hir as hir;
1818
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
1919
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
2020
use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
21+
use rustc_hir::diagnostic_items::DiagnosticItems;
2122
use rustc_hir::lang_items;
2223
use rustc_index::vec::{Idx, IndexVec};
2324
use rustc_middle::hir::exports::Export;
@@ -1052,16 +1053,23 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
10521053
}
10531054

10541055
/// Iterates over the diagnostic items in the given crate.
1055-
fn get_diagnostic_items(&self) -> FxHashMap<Symbol, DefId> {
1056+
fn get_diagnostic_items(&self) -> DiagnosticItems {
10561057
if self.root.is_proc_macro_crate() {
10571058
// Proc macro crates do not export any diagnostic-items to the target.
10581059
Default::default()
10591060
} else {
1060-
self.root
1061+
let mut id_to_name = FxHashMap::default();
1062+
let name_to_id = self
1063+
.root
10611064
.diagnostic_items
10621065
.decode(self)
1063-
.map(|(name, def_index)| (name, self.local_def_id(def_index)))
1064-
.collect()
1066+
.map(|(name, def_index)| {
1067+
let id = self.local_def_id(def_index);
1068+
id_to_name.insert(id, name);
1069+
(name, id)
1070+
})
1071+
.collect();
1072+
DiagnosticItems { id_to_name, name_to_id }
10651073
}
10661074
}
10671075

compiler/rustc_metadata/src/rmeta/encoder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1750,7 +1750,7 @@ impl EncodeContext<'a, 'tcx> {
17501750
fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> {
17511751
empty_proc_macro!(self);
17521752
let tcx = self.tcx;
1753-
let diagnostic_items = tcx.diagnostic_items(LOCAL_CRATE);
1753+
let diagnostic_items = &tcx.diagnostic_items(LOCAL_CRATE).name_to_id;
17541754
self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index)))
17551755
}
17561756

compiler/rustc_middle/src/query/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1442,7 +1442,7 @@ rustc_queries! {
14421442
}
14431443

14441444
/// Returns all diagnostic items defined in all crates.
1445-
query all_diagnostic_items(_: ()) -> FxHashMap<Symbol, DefId> {
1445+
query all_diagnostic_items(_: ()) -> rustc_hir::diagnostic_items::DiagnosticItems {
14461446
storage(ArenaCacheSelector<'tcx>)
14471447
eval_always
14481448
desc { "calculating the diagnostic items map" }
@@ -1454,7 +1454,7 @@ rustc_queries! {
14541454
}
14551455

14561456
/// Returns the diagnostic items defined in a crate.
1457-
query diagnostic_items(_: CrateNum) -> FxHashMap<Symbol, DefId> {
1457+
query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems {
14581458
storage(ArenaCacheSelector<'tcx>)
14591459
desc { "calculating the diagnostic items map in a crate" }
14601460
}

compiler/rustc_middle/src/ty/context.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1232,12 +1232,17 @@ impl<'tcx> TyCtxt<'tcx> {
12321232
/// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to
12331233
/// compare against another `DefId`, since `is_diagnostic_item` is cheaper.
12341234
pub fn get_diagnostic_item(self, name: Symbol) -> Option<DefId> {
1235-
self.all_diagnostic_items(()).get(&name).copied()
1235+
self.all_diagnostic_items(()).name_to_id.get(&name).copied()
1236+
}
1237+
1238+
/// Obtain the diagnostic item's name
1239+
pub fn get_diagnostic_name(self, id: DefId) -> Option<Symbol> {
1240+
self.diagnostic_items(id.krate).id_to_name.get(&id).copied()
12361241
}
12371242

12381243
/// Check whether the diagnostic item with the given `name` has the given `DefId`.
12391244
pub fn is_diagnostic_item(self, name: Symbol, did: DefId) -> bool {
1240-
self.diagnostic_items(did.krate).get(&name) == Some(&did)
1245+
self.diagnostic_items(did.krate).name_to_id.get(&name) == Some(&did)
12411246
}
12421247

12431248
pub fn stability(self) -> &'tcx stability::Index<'tcx> {

compiler/rustc_passes/src/diagnostic_items.rs

+14-20
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,17 @@
1010
//! * Compiler internal types like `Ty` and `TyCtxt`
1111
1212
use rustc_ast as ast;
13-
use rustc_data_structures::fx::FxHashMap;
1413
use rustc_hir as hir;
14+
use rustc_hir::diagnostic_items::DiagnosticItems;
1515
use rustc_hir::itemlikevisit::ItemLikeVisitor;
1616
use rustc_middle::ty::query::Providers;
1717
use rustc_middle::ty::TyCtxt;
1818
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
1919
use rustc_span::symbol::{sym, Symbol};
2020

2121
struct DiagnosticItemCollector<'tcx> {
22-
// items from this crate
23-
items: FxHashMap<Symbol, DefId>,
2422
tcx: TyCtxt<'tcx>,
23+
diagnostic_items: DiagnosticItems,
2524
}
2625

2726
impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> {
@@ -44,27 +43,22 @@ impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> {
4443

4544
impl<'tcx> DiagnosticItemCollector<'tcx> {
4645
fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> {
47-
DiagnosticItemCollector { tcx, items: Default::default() }
46+
DiagnosticItemCollector { tcx, diagnostic_items: DiagnosticItems::default() }
4847
}
4948

5049
fn observe_item(&mut self, def_id: LocalDefId) {
5150
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
5251
let attrs = self.tcx.hir().attrs(hir_id);
5352
if let Some(name) = extract(attrs) {
5453
// insert into our table
55-
collect_item(self.tcx, &mut self.items, name, def_id.to_def_id());
54+
collect_item(self.tcx, &mut self.diagnostic_items, name, def_id.to_def_id());
5655
}
5756
}
5857
}
5958

60-
fn collect_item(
61-
tcx: TyCtxt<'_>,
62-
items: &mut FxHashMap<Symbol, DefId>,
63-
name: Symbol,
64-
item_def_id: DefId,
65-
) {
66-
// Check for duplicates.
67-
if let Some(original_def_id) = items.insert(name, item_def_id) {
59+
fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item_def_id: DefId) {
60+
items.id_to_name.insert(item_def_id, name);
61+
if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) {
6862
if original_def_id != item_def_id {
6963
let mut err = match tcx.hir().span_if_local(item_def_id) {
7064
Some(span) => tcx.sess.struct_span_err(
@@ -98,7 +92,7 @@ fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
9892
}
9993

10094
/// Traverse and collect the diagnostic items in the current
101-
fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> FxHashMap<Symbol, DefId> {
95+
fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems {
10296
assert_eq!(cnum, LOCAL_CRATE);
10397

10498
// Initialize the collector.
@@ -107,22 +101,22 @@ fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> FxHashMap<Symbol
107101
// Collect diagnostic items in this crate.
108102
tcx.hir().visit_all_item_likes(&mut collector);
109103

110-
collector.items
104+
collector.diagnostic_items
111105
}
112106

113107
/// Traverse and collect all the diagnostic items in all crates.
114-
fn all_diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashMap<Symbol, DefId> {
108+
fn all_diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> DiagnosticItems {
115109
// Initialize the collector.
116-
let mut collector = FxHashMap::default();
110+
let mut items = DiagnosticItems::default();
117111

118112
// Collect diagnostic items in other crates.
119113
for &cnum in tcx.crates(()).iter().chain(std::iter::once(&LOCAL_CRATE)) {
120-
for (&name, &def_id) in tcx.diagnostic_items(cnum).iter() {
121-
collect_item(tcx, &mut collector, name, def_id);
114+
for (&name, &def_id) in &tcx.diagnostic_items(cnum).name_to_id {
115+
collect_item(tcx, &mut items, name, def_id);
122116
}
123117
}
124118

125-
collector
119+
items
126120
}
127121

128122
pub fn provide(providers: &mut Providers) {

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1636,12 +1636,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
16361636

16371637
// Special case the primary error message when send or sync is the trait that was
16381638
// not implemented.
1639-
let is_send = self.tcx.is_diagnostic_item(sym::Send, trait_ref.def_id);
1640-
let is_sync = self.tcx.is_diagnostic_item(sym::Sync, trait_ref.def_id);
16411639
let hir = self.tcx.hir();
1642-
let trait_explanation = if is_send || is_sync {
1640+
let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) =
1641+
self.tcx.get_diagnostic_name(trait_ref.def_id)
1642+
{
16431643
let (trait_name, trait_verb) =
1644-
if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
1644+
if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
16451645

16461646
err.clear_code();
16471647
err.set_primary_message(format!(

0 commit comments

Comments
 (0)