12
12
13
13
use std:: collections:: { BTreeMap , BTreeSet } ;
14
14
15
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
15
16
use rustc_hir:: HirId ;
16
17
use rustc_lint_defs:: Applicability ;
17
18
use rustc_resolve:: rustdoc:: source_span_for_markdown_range;
@@ -39,6 +40,8 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
39
40
// the new parser and old parser.
40
41
let mut missing_footnote_references = BTreeMap :: new ( ) ;
41
42
let mut found_footnote_references = BTreeSet :: new ( ) ;
43
+ let mut footnote_references = FxHashSet :: default ( ) ;
44
+ let mut footnote_definitions = FxHashMap :: default ( ) ;
42
45
43
46
// populate problem cases from new parser
44
47
{
@@ -51,13 +54,20 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
51
54
}
52
55
let parser_new = cmarkn:: Parser :: new_ext ( dox, main_body_opts_new ( ) ) . into_offset_iter ( ) ;
53
56
for ( event, span) in parser_new {
54
- if let cmarkn:: Event :: Start ( cmarkn:: Tag :: BlockQuote ( _) ) = event {
55
- if !dox[ span. clone ( ) ] . starts_with ( "> " ) {
56
- spaceless_block_quotes. insert ( span. start ) ;
57
+ match event {
58
+ cmarkn:: Event :: Start ( cmarkn:: Tag :: BlockQuote ( _) ) => {
59
+ if !dox[ span. clone ( ) ] . starts_with ( "> " ) {
60
+ spaceless_block_quotes. insert ( span. start ) ;
61
+ }
57
62
}
58
- }
59
- if let cmarkn:: Event :: FootnoteReference ( _) = event {
60
- found_footnote_references. insert ( span. start + 1 ) ;
63
+ cmarkn:: Event :: FootnoteReference ( label) => {
64
+ found_footnote_references. insert ( span. start + 1 ) ;
65
+ footnote_references. insert ( label) ;
66
+ }
67
+ cmarkn:: Event :: Start ( cmarkn:: Tag :: FootnoteDefinition ( label) ) => {
68
+ footnote_definitions. insert ( label, span. start + 1 ) ;
69
+ }
70
+ _ => { }
61
71
}
62
72
}
63
73
}
@@ -86,6 +96,23 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
86
96
}
87
97
}
88
98
99
+ #[ allow( rustc:: potential_query_instability) ]
100
+ for ( footnote, span) in footnote_definitions {
101
+ if !footnote_references. contains ( & footnote) {
102
+ let span = source_span_for_markdown_range (
103
+ tcx,
104
+ dox,
105
+ & ( span..span + 1 ) ,
106
+ & item. attrs . doc_strings ,
107
+ )
108
+ . unwrap_or_else ( || item. attr_span ( tcx) ) ;
109
+
110
+ tcx. node_span_lint ( crate :: lint:: UNUSED_FOOTNOTE_DEFINITION , hir_id, span, |lint| {
111
+ lint. primary_message ( "unused footnote definition" ) ;
112
+ } ) ;
113
+ }
114
+ }
115
+
89
116
for start in spaceless_block_quotes {
90
117
let ( span, precise) =
91
118
source_span_for_markdown_range ( tcx, dox, & ( start..start + 1 ) , & item. attrs . doc_strings )
0 commit comments