Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge diagnostic_items duplicate diagnostics #108486

Merged
merged 2 commits into from
Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions compiler/rustc_middle/src/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,17 @@ impl ModuleItems {
self.foreign_items.iter().copied()
}

pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
pub fn owners(&self) -> impl Iterator<Item = OwnerId> + '_ {
self.items
.iter()
.map(|id| id.owner_id.def_id)
.chain(self.trait_items.iter().map(|id| id.owner_id.def_id))
.chain(self.impl_items.iter().map(|id| id.owner_id.def_id))
.chain(self.foreign_items.iter().map(|id| id.owner_id.def_id))
.map(|id| id.owner_id)
.chain(self.trait_items.iter().map(|id| id.owner_id))
.chain(self.impl_items.iter().map(|id| id.owner_id))
.chain(self.foreign_items.iter().map(|id| id.owner_id))
}

pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
self.owners().map(|id| id.def_id)
}

pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) {
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_passes/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -402,9 +402,6 @@ passes_invalid_attr_at_crate_level =
`{$name}` attribute cannot be used at crate level
.suggestion = perhaps you meant to use an outer attribute

passes_duplicate_diagnostic_item =
duplicate diagnostic item found: `{$name}`.

passes_duplicate_diagnostic_item_in_crate =
duplicate diagnostic item in crate `{$crate_name}`: `{$name}`.
.note = the diagnostic item is first defined in crate `{$orig_crate_name}`.
Expand Down
63 changes: 28 additions & 35 deletions compiler/rustc_passes/src/diagnostic_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,43 +11,49 @@

use rustc_ast as ast;
use rustc_hir::diagnostic_items::DiagnosticItems;
use rustc_hir::OwnerId;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_span::symbol::{kw::Empty, sym, Symbol};
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_span::symbol::{sym, Symbol};

use crate::errors::{DuplicateDiagnosticItem, DuplicateDiagnosticItemInCrate};
use crate::errors::DuplicateDiagnosticItemInCrate;

fn observe_item(tcx: TyCtxt<'_>, diagnostic_items: &mut DiagnosticItems, def_id: LocalDefId) {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let attrs = tcx.hir().attrs(hir_id);
fn observe_item<'tcx>(tcx: TyCtxt<'tcx>, diagnostic_items: &mut DiagnosticItems, owner: OwnerId) {
let attrs = tcx.hir().attrs(owner.into());
if let Some(name) = extract(attrs) {
// insert into our table
collect_item(tcx, diagnostic_items, name, def_id.to_def_id());
collect_item(tcx, diagnostic_items, name, owner.to_def_id());
}
}

fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item_def_id: DefId) {
items.id_to_name.insert(item_def_id, name);
if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) {
if original_def_id != item_def_id {
let orig_span = tcx.hir().span_if_local(original_def_id);
let orig_crate_name =
orig_span.is_none().then(|| tcx.crate_name(original_def_id.krate));
match tcx.hir().span_if_local(item_def_id) {
Some(span) => tcx.sess.emit_err(DuplicateDiagnosticItem { span, name }),
None => tcx.sess.emit_err(DuplicateDiagnosticItemInCrate {
span: orig_span,
orig_crate_name: orig_crate_name.unwrap_or(Empty),
have_orig_crate_name: orig_crate_name.map(|_| ()),
crate_name: tcx.crate_name(item_def_id.krate),
name,
}),
};
report_duplicate_item(tcx, name, original_def_id, item_def_id);
}
}
}

fn report_duplicate_item(
tcx: TyCtxt<'_>,
name: Symbol,
original_def_id: DefId,
item_def_id: DefId,
) {
let orig_span = tcx.hir().span_if_local(original_def_id);
let duplicate_span = tcx.hir().span_if_local(item_def_id);
tcx.sess.emit_err(DuplicateDiagnosticItemInCrate {
duplicate_span,
orig_span,
crate_name: tcx.crate_name(item_def_id.krate),
orig_crate_name: tcx.crate_name(original_def_id.krate),
different_crates: (item_def_id.krate != original_def_id.krate).then_some(()),
name,
});
}

/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.
fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
attrs.iter().find_map(|attr| {
Expand All @@ -64,21 +70,8 @@ fn diagnostic_items(tcx: TyCtxt<'_>, cnum: CrateNum) -> DiagnosticItems {

// Collect diagnostic items in this crate.
let crate_items = tcx.hir_crate_items(());

for id in crate_items.items() {
observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
}

for id in crate_items.trait_items() {
observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
}

for id in crate_items.impl_items() {
observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
}

for id in crate_items.foreign_items() {
observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
for id in crate_items.owners() {
observe_item(tcx, &mut diagnostic_items, id);
}

diagnostic_items
Expand Down
16 changes: 5 additions & 11 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,23 +809,17 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
}
}

#[derive(Diagnostic)]
#[diag(passes_duplicate_diagnostic_item)]
pub struct DuplicateDiagnosticItem {
#[primary_span]
pub span: Span,
pub name: Symbol,
}

#[derive(Diagnostic)]
#[diag(passes_duplicate_diagnostic_item_in_crate)]
pub struct DuplicateDiagnosticItemInCrate {
#[primary_span]
pub duplicate_span: Option<Span>,
#[note(passes_diagnostic_item_first_defined)]
pub span: Option<Span>,
pub orig_crate_name: Symbol,
pub orig_span: Option<Span>,
#[note]
pub have_orig_crate_name: Option<()>,
pub different_crates: Option<()>,
pub crate_name: Symbol,
pub orig_crate_name: Symbol,
pub name: Symbol,
}

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/tool-attributes/duplicate-diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ extern crate p1;
extern crate p2;

#[rustc_diagnostic_item = "Foo"]
pub struct Foo {} //~ ERROR duplicate diagnostic item found
pub struct Foo {} //~ ERROR duplicate diagnostic item in crate `duplicate_diagnostic`: `Foo`
fn main() {}
4 changes: 3 additions & 1 deletion tests/ui/tool-attributes/duplicate-diagnostic.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ error: duplicate diagnostic item in crate `p2`: `Foo`.
|
= note: the diagnostic item is first defined in crate `p1`.

error: duplicate diagnostic item found: `Foo`.
error: duplicate diagnostic item in crate `duplicate_diagnostic`: `Foo`.
--> $DIR/duplicate-diagnostic.rs:12:1
|
LL | pub struct Foo {}
| ^^^^^^^^^^^^^^
|
= note: the diagnostic item is first defined in crate `p2`.

error: aborting due to 2 previous errors