@@ -9,7 +9,7 @@ use rustc_middle::ty::query::Providers;
9
9
use rustc_middle::ty::TyCtxt;
10
10
11
11
use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
12
- use rustc_data_structures::stable_set:: FxHashSet;
12
+ use rustc_data_structures::fx::{FxHashMap, FxHashSet} ;
13
13
use rustc_errors::{pluralize, struct_span_err, Applicability};
14
14
use rustc_feature::{AttributeType, BUILTIN_ATTRIBUTE_MAP};
15
15
use rustc_hir as hir;
@@ -66,6 +66,7 @@ impl CheckAttrVisitor<'tcx> {
66
66
target: Target,
67
67
item: Option<ItemLike<'_>>,
68
68
) {
69
+ let mut doc_aliases = FxHashMap::default();
69
70
let mut is_valid = true;
70
71
let mut specified_inline = None;
71
72
let mut seen = FxHashSet::default();
@@ -79,7 +80,13 @@ impl CheckAttrVisitor<'tcx> {
79
80
sym::track_caller => {
80
81
self.check_track_caller(hir_id, &attr.span, attrs, span, target)
81
82
}
82
- sym::doc => self.check_doc_attrs(attr, hir_id, target, &mut specified_inline),
83
+ sym::doc => self.check_doc_attrs(
84
+ attr,
85
+ hir_id,
86
+ target,
87
+ &mut specified_inline,
88
+ &mut doc_aliases,
89
+ ),
83
90
sym::no_link => self.check_no_link(hir_id, &attr, span, target),
84
91
sym::export_name => self.check_export_name(hir_id, &attr, span, target),
85
92
sym::rustc_layout_scalar_valid_range_start
@@ -512,6 +519,7 @@ impl CheckAttrVisitor<'tcx> {
512
519
hir_id: HirId,
513
520
target: Target,
514
521
is_list: bool,
522
+ aliases: &mut FxHashMap<String, Span>,
515
523
) -> bool {
516
524
let tcx = self.tcx;
517
525
let err_fn = move |span: Span, msg: &str| {
@@ -582,17 +590,38 @@ impl CheckAttrVisitor<'tcx> {
582
590
if &*item_name.as_str() == doc_alias {
583
591
return err_fn(meta.span(), "is the same as the item's name");
584
592
}
593
+ let span = meta.span();
594
+ if let Err(entry) = aliases.try_insert(doc_alias.to_owned(), span) {
595
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| {
596
+ lint.build("doc alias is duplicated")
597
+ .span_label(*entry.entry.get(), "first defined here")
598
+ .emit();
599
+ });
600
+ }
585
601
true
586
602
}
587
603
588
- fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool {
604
+ fn check_doc_alias(
605
+ &self,
606
+ meta: &NestedMetaItem,
607
+ hir_id: HirId,
608
+ target: Target,
609
+ aliases: &mut FxHashMap<String, Span>,
610
+ ) -> bool {
589
611
if let Some(values) = meta.meta_item_list() {
590
612
let mut errors = 0;
591
613
for v in values {
592
614
match v.literal() {
593
615
Some(l) => match l.kind {
594
616
LitKind::Str(s, _) => {
595
- if !self.check_doc_alias_value(v, &s.as_str(), hir_id, target, true) {
617
+ if !self.check_doc_alias_value(
618
+ v,
619
+ &s.as_str(),
620
+ hir_id,
621
+ target,
622
+ true,
623
+ aliases,
624
+ ) {
596
625
errors += 1;
597
626
}
598
627
}
@@ -621,7 +650,7 @@ impl CheckAttrVisitor<'tcx> {
621
650
}
622
651
errors == 0
623
652
} else if let Some(doc_alias) = meta.value_str().map(|s| s.to_string()) {
624
- self.check_doc_alias_value(meta, &doc_alias, hir_id, target, false)
653
+ self.check_doc_alias_value(meta, &doc_alias, hir_id, target, false, aliases )
625
654
} else {
626
655
self.tcx
627
656
.sess
@@ -858,6 +887,7 @@ impl CheckAttrVisitor<'tcx> {
858
887
hir_id: HirId,
859
888
target: Target,
860
889
specified_inline: &mut Option<(bool, Span)>,
890
+ aliases: &mut FxHashMap<String, Span>,
861
891
) -> bool {
862
892
let mut is_valid = true;
863
893
@@ -867,7 +897,7 @@ impl CheckAttrVisitor<'tcx> {
867
897
match i_meta.name_or_empty() {
868
898
sym::alias
869
899
if !self.check_attr_not_crate_level(&meta, hir_id, "alias")
870
- || !self.check_doc_alias(&meta, hir_id, target) =>
900
+ || !self.check_doc_alias(&meta, hir_id, target, aliases ) =>
871
901
{
872
902
is_valid = false
873
903
}
0 commit comments