@@ -12,9 +12,11 @@ use rustc_resolve::rustdoc::{prepare_to_doc_link_resolution, source_span_for_mar
1212use rustc_span:: def_id:: DefId ;
1313use rustc_span:: { Span , Symbol } ;
1414
15- use crate :: clean:: Item ;
1615use crate :: clean:: utils:: { find_nearest_parent_module, inherits_doc_hidden} ;
16+ use crate :: clean:: { Item , inline} ;
1717use crate :: core:: DocContext ;
18+ use crate :: formats:: item_type:: ItemType ;
19+ use crate :: html:: format:: href_relative_parts;
1820use crate :: html:: markdown:: main_body_opts;
1921
2022#[ derive( Debug ) ]
@@ -71,12 +73,13 @@ fn check_redundant_explicit_link_for_did(
7173 return ;
7274 } ;
7375
74- check_redundant_explicit_link ( cx, item, hir_id, doc, resolutions) ;
76+ check_redundant_explicit_link ( cx, item, module_id , hir_id, doc, resolutions) ;
7577}
7678
7779fn check_redundant_explicit_link < ' md > (
7880 cx : & DocContext < ' _ > ,
7981 item : & Item ,
82+ module_id : DefId ,
8083 hir_id : HirId ,
8184 doc : & ' md str ,
8285 resolutions : & DocLinkResMap ,
@@ -114,35 +117,35 @@ fn check_redundant_explicit_link<'md>(
114117 continue ;
115118 }
116119
117- if dest_url. ends_with ( resolvable_link) || resolvable_link. ends_with ( & * dest_url) {
118- match link_type {
119- LinkType :: Inline | LinkType :: ReferenceUnknown => {
120- check_inline_or_reference_unknown_redundancy (
121- cx,
122- item,
123- hir_id,
124- doc,
125- resolutions,
126- link_range,
127- dest_url. to_string ( ) ,
128- link_data,
129- if link_type == LinkType :: Inline { ( b'(' , b')' ) } else { ( b'[' , b']' ) } ,
130- ) ;
131- }
132- LinkType :: Reference => {
133- check_reference_redundancy (
134- cx,
135- item,
136- hir_id,
137- doc,
138- resolutions,
139- link_range,
140- & dest_url,
141- link_data,
142- ) ;
143- }
144- _ => { }
120+ match link_type {
121+ LinkType :: Inline | LinkType :: ReferenceUnknown => {
122+ check_inline_or_reference_unknown_redundancy (
123+ cx,
124+ item,
125+ module_id,
126+ hir_id,
127+ doc,
128+ resolutions,
129+ link_range,
130+ dest_url. to_string ( ) ,
131+ link_data,
132+ if link_type == LinkType :: Inline { ( b'(' , b')' ) } else { ( b'[' , b']' ) } ,
133+ ) ;
134+ }
135+ LinkType :: Reference => {
136+ check_reference_redundancy (
137+ cx,
138+ item,
139+ module_id,
140+ hir_id,
141+ doc,
142+ resolutions,
143+ link_range,
144+ & dest_url,
145+ link_data,
146+ ) ;
145147 }
148+ _ => { }
146149 }
147150 }
148151 }
@@ -154,6 +157,7 @@ fn check_redundant_explicit_link<'md>(
154157fn check_inline_or_reference_unknown_redundancy (
155158 cx : & DocContext < ' _ > ,
156159 item : & Item ,
160+ module_id : DefId ,
157161 hir_id : HirId ,
158162 doc : & str ,
159163 resolutions : & DocLinkResMap ,
@@ -198,10 +202,8 @@ fn check_inline_or_reference_unknown_redundancy(
198202
199203 let ( resolvable_link, resolvable_link_range) =
200204 ( & link_data. resolvable_link ?, & link_data. resolvable_link_range ?) ;
201- let ( dest_res, display_res) =
202- ( find_resolution ( resolutions, & dest) ?, find_resolution ( resolutions, resolvable_link) ?) ;
203205
204- if dest_res == display_res {
206+ if explicit_link_is_redundant ( cx , module_id , resolutions , & dest , resolvable_link ) {
205207 let link_span =
206208 match source_span_for_markdown_range ( cx. tcx , doc, & link_range, & item. attrs . doc_strings )
207209 {
@@ -254,6 +256,7 @@ fn check_inline_or_reference_unknown_redundancy(
254256fn check_reference_redundancy (
255257 cx : & DocContext < ' _ > ,
256258 item : & Item ,
259+ module_id : DefId ,
257260 hir_id : HirId ,
258261 doc : & str ,
259262 resolutions : & DocLinkResMap ,
@@ -296,10 +299,8 @@ fn check_reference_redundancy(
296299
297300 let ( resolvable_link, resolvable_link_range) =
298301 ( & link_data. resolvable_link ?, & link_data. resolvable_link_range ?) ;
299- let ( dest_res, display_res) =
300- ( find_resolution ( resolutions, dest) ?, find_resolution ( resolutions, resolvable_link) ?) ;
301302
302- if dest_res == display_res {
303+ if explicit_link_is_redundant ( cx , module_id , resolutions , dest , resolvable_link ) {
303304 let link_span =
304305 match source_span_for_markdown_range ( cx. tcx , doc, & link_range, & item. attrs . doc_strings )
305306 {
@@ -355,6 +356,61 @@ fn check_reference_redundancy(
355356 None
356357}
357358
359+ fn explicit_link_is_redundant (
360+ cx : & DocContext < ' _ > ,
361+ module_id : DefId ,
362+ resolutions : & DocLinkResMap ,
363+ dest : & str ,
364+ resolvable_link : & str ,
365+ ) -> bool {
366+ let Some ( display_res) = find_resolution ( resolutions, resolvable_link) else {
367+ return false ;
368+ } ;
369+
370+ if ( dest. ends_with ( resolvable_link) || resolvable_link. ends_with ( dest) )
371+ && find_resolution ( resolutions, dest) . is_some_and ( |dest_res| dest_res == display_res)
372+ {
373+ return true ;
374+ }
375+
376+ if !dest. contains ( '#' ) && dest. ends_with ( ".html" ) {
377+ return false ;
378+ }
379+
380+ local_href_for_res ( cx, module_id, display_res) . is_some_and ( |href| href == dest)
381+ }
382+
383+ fn local_href_for_res ( cx : & DocContext < ' _ > , module_id : DefId , res : Res < NodeId > ) -> Option < String > {
384+ let mut did = res. opt_def_id ( ) ?;
385+ if matches ! ( cx. tcx. def_kind( did) , DefKind :: Ctor ( ..) ) {
386+ did = cx. tcx . parent ( did) ;
387+ }
388+
389+ if matches ! (
390+ cx. tcx. def_kind( did) ,
391+ DefKind :: AssocTy | DefKind :: AssocFn | DefKind :: AssocConst { .. } | DefKind :: Variant
392+ ) || !did. is_local ( )
393+ {
394+ return None ;
395+ }
396+
397+ let item_type = ItemType :: from_def_id ( did, cx. tcx ) ;
398+ let fqp = inline:: get_item_path ( cx. tcx , did, item_type) ;
399+ let module_fqp = if item_type == ItemType :: Module { & fqp[ ..] } else { & fqp[ ..fqp. len ( ) - 1 ] } ;
400+ let current_fqp = inline:: get_item_path ( cx. tcx , module_id, ItemType :: Module ) ;
401+
402+ let mut url_parts = href_relative_parts ( module_fqp, & current_fqp) ;
403+ match item_type {
404+ ItemType :: Module => url_parts. push ( "index.html" ) ,
405+ _ => url_parts. push_fmt ( format_args ! (
406+ "{}.{last}.html" ,
407+ item_type. as_str( ) ,
408+ last = fqp. last( ) ?
409+ ) ) ,
410+ }
411+ Some ( url_parts. finish ( ) )
412+ }
413+
358414fn find_resolution ( resolutions : & DocLinkResMap , path : & str ) -> Option < Res < NodeId > > {
359415 [ Namespace :: TypeNS , Namespace :: ValueNS , Namespace :: MacroNS ]
360416 . into_iter ( )
0 commit comments