@@ -17,10 +17,10 @@ use rustc_abi::ExternAbi;
1717use rustc_ast:: join_path_syms;
1818use rustc_data_structures:: fx:: FxHashSet ;
1919use rustc_hir as hir;
20- use rustc_hir:: def:: DefKind ;
20+ use rustc_hir:: def:: { DefKind , MacroKinds } ;
2121use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
2222use rustc_hir:: { ConstStability , StabilityLevel , StableSince } ;
23- use rustc_metadata:: creader:: { CStore , LoadedMacro } ;
23+ use rustc_metadata:: creader:: CStore ;
2424use rustc_middle:: ty:: { self , TyCtxt , TypingMode } ;
2525use rustc_span:: symbol:: kw;
2626use rustc_span:: { Symbol , sym} ;
@@ -349,47 +349,56 @@ pub(crate) enum HrefError {
349349 UnnamableItem ,
350350}
351351
352+ /// Type representing information of an `href` attribute.
353+ pub ( crate ) struct HrefInfo {
354+ /// URL to the item page.
355+ pub ( crate ) url : String ,
356+ /// Kind of the item (used to generate the `title` attribute).
357+ pub ( crate ) kind : ItemType ,
358+ /// Rust path to the item (used to generate the `title` attribute).
359+ pub ( crate ) rust_path : Vec < Symbol > ,
360+ }
361+
352362/// This function is to get the external macro path because they are not in the cache used in
353363/// `href_with_root_path`.
354364fn generate_macro_def_id_path (
355365 def_id : DefId ,
356366 cx : & Context < ' _ > ,
357367 root_path : Option < & str > ,
358- ) -> Result < ( String , ItemType , Vec < Symbol > ) , HrefError > {
368+ ) -> Result < HrefInfo , HrefError > {
359369 let tcx = cx. tcx ( ) ;
360370 let crate_name = tcx. crate_name ( def_id. krate ) ;
361371 let cache = cx. cache ( ) ;
362372
363- let fqp = clean:: inline:: item_relative_path ( tcx, def_id) ;
364- let mut relative = fqp. iter ( ) . copied ( ) ;
365373 let cstore = CStore :: from_tcx ( tcx) ;
366374 // We need this to prevent a `panic` when this function is used from intra doc links...
367375 if !cstore. has_crate_data ( def_id. krate ) {
368376 debug ! ( "No data for crate {crate_name}" ) ;
369377 return Err ( HrefError :: NotInExternalCache ) ;
370378 }
371- // Check to see if it is a macro 2.0 or built-in macro.
372- // More information in <https://rust-lang.github.io/rfcs/1584-macros.html>.
373- let is_macro_2 = match cstore. load_macro_untracked ( def_id, tcx) {
374- // If `def.macro_rules` is `true`, then it's not a macro 2.0.
375- LoadedMacro :: MacroDef { def, .. } => !def. macro_rules ,
376- _ => false ,
379+ let DefKind :: Macro ( kinds) = tcx. def_kind ( def_id) else {
380+ unreachable ! ( ) ;
377381 } ;
378-
379- let mut path = if is_macro_2 {
380- once ( crate_name) . chain ( relative) . collect ( )
382+ let item_type = if kinds == MacroKinds :: DERIVE {
383+ ItemType :: ProcDerive
384+ } else if kinds == MacroKinds :: ATTR {
385+ ItemType :: ProcAttribute
381386 } else {
382- vec ! [ crate_name , relative . next_back ( ) . unwrap ( ) ]
387+ ItemType :: Macro
383388 } ;
389+ let mut path = clean:: inline:: get_item_path ( tcx, def_id, item_type) ;
384390 if path. len ( ) < 2 {
385391 // The minimum we can have is the crate name followed by the macro name. If shorter, then
386392 // it means that `relative` was empty, which is an error.
387393 debug ! ( "macro path cannot be empty!" ) ;
388394 return Err ( HrefError :: NotInExternalCache ) ;
389395 }
390396
391- if let Some ( last) = path. last_mut ( ) {
392- * last = Symbol :: intern ( & format ! ( "macro.{last}.html" ) ) ;
397+ // FIXME: Try to use `iter().chain().once()` instead.
398+ let mut prev = None ;
399+ if let Some ( last) = path. pop ( ) {
400+ path. push ( Symbol :: intern ( & format ! ( "{}.{last}.html" , item_type. as_str( ) ) ) ) ;
401+ prev = Some ( last) ;
393402 }
394403
395404 let url = match cache. extern_locations [ & def_id. krate ] {
@@ -410,7 +419,11 @@ fn generate_macro_def_id_path(
410419 return Err ( HrefError :: NotInExternalCache ) ;
411420 }
412421 } ;
413- Ok ( ( url, ItemType :: Macro , fqp) )
422+ if let Some ( prev) = prev {
423+ path. pop ( ) ;
424+ path. push ( prev) ;
425+ }
426+ Ok ( HrefInfo { url, kind : item_type, rust_path : path } )
414427}
415428
416429fn generate_item_def_id_path (
@@ -419,7 +432,7 @@ fn generate_item_def_id_path(
419432 cx : & Context < ' _ > ,
420433 root_path : Option < & str > ,
421434 original_def_kind : DefKind ,
422- ) -> Result < ( String , ItemType , Vec < Symbol > ) , HrefError > {
435+ ) -> Result < HrefInfo , HrefError > {
423436 use rustc_middle:: traits:: ObligationCause ;
424437 use rustc_trait_selection:: infer:: TyCtxtInferExt ;
425438 use rustc_trait_selection:: traits:: query:: normalize:: QueryNormalizeExt ;
@@ -455,7 +468,7 @@ fn generate_item_def_id_path(
455468 let kind = ItemType :: from_def_kind ( original_def_kind, Some ( def_kind) ) ;
456469 url_parts = format ! ( "{url_parts}#{kind}.{}" , tcx. item_name( original_def_id) )
457470 } ;
458- Ok ( ( url_parts, shortty, fqp) )
471+ Ok ( HrefInfo { url : url_parts, kind : shortty, rust_path : fqp } )
459472}
460473
461474/// Checks if the given defid refers to an item that is unnamable, such as one defined in a const block.
@@ -530,7 +543,7 @@ pub(crate) fn href_with_root_path(
530543 original_did : DefId ,
531544 cx : & Context < ' _ > ,
532545 root_path : Option < & str > ,
533- ) -> Result < ( String , ItemType , Vec < Symbol > ) , HrefError > {
546+ ) -> Result < HrefInfo , HrefError > {
534547 let tcx = cx. tcx ( ) ;
535548 let def_kind = tcx. def_kind ( original_did) ;
536549 let did = match def_kind {
@@ -596,14 +609,14 @@ pub(crate) fn href_with_root_path(
596609 }
597610 }
598611 } ;
599- let url_parts = make_href ( root_path, shortty, url_parts, fqp, is_remote) ;
600- Ok ( ( url_parts, shortty, fqp. clone ( ) ) )
612+ Ok ( HrefInfo {
613+ url : make_href ( root_path, shortty, url_parts, fqp, is_remote) ,
614+ kind : shortty,
615+ rust_path : fqp. clone ( ) ,
616+ } )
601617}
602618
603- pub ( crate ) fn href (
604- did : DefId ,
605- cx : & Context < ' _ > ,
606- ) -> Result < ( String , ItemType , Vec < Symbol > ) , HrefError > {
619+ pub ( crate ) fn href ( did : DefId , cx : & Context < ' _ > ) -> Result < HrefInfo , HrefError > {
607620 href_with_root_path ( did, cx, None )
608621}
609622
@@ -690,12 +703,12 @@ fn resolved_path(
690703 } else {
691704 let path = fmt:: from_fn ( |f| {
692705 if use_absolute {
693- if let Ok ( ( _ , _ , fqp ) ) = href ( did, cx) {
706+ if let Ok ( HrefInfo { rust_path , .. } ) = href ( did, cx) {
694707 write ! (
695708 f,
696709 "{path}::{anchor}" ,
697- path = join_path_syms( & fqp [ ..fqp . len( ) - 1 ] ) ,
698- anchor = print_anchor( did, * fqp . last( ) . unwrap( ) , cx)
710+ path = join_path_syms( & rust_path [ ..rust_path . len( ) - 1 ] ) ,
711+ anchor = print_anchor( did, * rust_path . last( ) . unwrap( ) , cx)
699712 )
700713 } else {
701714 write ! ( f, "{}" , last. name)
@@ -824,12 +837,11 @@ fn print_higher_ranked_params_with_space(
824837
825838pub ( crate ) fn print_anchor ( did : DefId , text : Symbol , cx : & Context < ' _ > ) -> impl Display {
826839 fmt:: from_fn ( move |f| {
827- let parts = href ( did, cx) ;
828- if let Ok ( ( url, short_ty, fqp) ) = parts {
840+ if let Ok ( HrefInfo { url, kind, rust_path } ) = href ( did, cx) {
829841 write ! (
830842 f,
831- r#"<a class="{short_ty }" href="{url}" title="{short_ty } {path}">{text}</a>"# ,
832- path = join_path_syms( fqp ) ,
843+ r#"<a class="{kind }" href="{url}" title="{kind } {path}">{text}</a>"# ,
844+ path = join_path_syms( rust_path ) ,
833845 text = EscapeBodyText ( text. as_str( ) ) ,
834846 )
835847 } else {
@@ -1056,14 +1068,14 @@ fn print_qpath_data(qpath_data: &clean::QPathData, cx: &Context<'_>) -> impl Dis
10561068 None => self_type. def_id ( cx. cache ( ) ) . and_then ( |did| href ( did, cx) . ok ( ) ) ,
10571069 } ;
10581070
1059- if let Some ( ( url, _ , path ) ) = parent_href {
1071+ if let Some ( HrefInfo { url, rust_path , .. } ) = parent_href {
10601072 write ! (
10611073 f,
10621074 "<a class=\" associatedtype\" href=\" {url}#{shortty}.{name}\" \
10631075 title=\" type {path}::{name}\" >{name}</a>",
10641076 shortty = ItemType :: AssocType ,
10651077 name = assoc. name,
1066- path = join_path_syms( path ) ,
1078+ path = join_path_syms( rust_path ) ,
10671079 )
10681080 } else {
10691081 write ! ( f, "{}" , assoc. name)
0 commit comments