@@ -4,6 +4,7 @@ use std::fmt;
44use std:: hash:: { Hash , Hasher } ;
55use std:: iter:: FromIterator ;
66use std:: lazy:: SyncOnceCell as OnceCell ;
7+ use std:: path:: PathBuf ;
78use std:: rc:: Rc ;
89use std:: sync:: Arc ;
910use std:: { slice, vec} ;
@@ -90,6 +91,58 @@ impl ExternalCrate {
9091 tcx. crate_name ( self . crate_num )
9192 }
9293
94+ crate fn src_root ( & self , tcx : TyCtxt < ' _ > ) -> PathBuf {
95+ match self . src ( tcx) {
96+ FileName :: Real ( ref p) => match p. local_path ( ) . parent ( ) {
97+ Some ( p) => p. to_path_buf ( ) ,
98+ None => PathBuf :: new ( ) ,
99+ } ,
100+ _ => PathBuf :: new ( ) ,
101+ }
102+ }
103+
104+ /// Attempts to find where an external crate is located, given that we're
105+ /// rendering in to the specified source destination.
106+ crate fn location (
107+ & self ,
108+ extern_url : Option < & str > ,
109+ dst : & std:: path:: Path ,
110+ tcx : TyCtxt < ' _ > ,
111+ ) -> ExternalLocation {
112+ use ExternalLocation :: * ;
113+
114+ fn to_remote ( url : impl ToString ) -> ExternalLocation {
115+ let mut url = url. to_string ( ) ;
116+ if !url. ends_with ( '/' ) {
117+ url. push ( '/' ) ;
118+ }
119+ Remote ( url)
120+ }
121+
122+ // See if there's documentation generated into the local directory
123+ // WARNING: since rustdoc creates these directories as it generates documentation, this check is only accurate before rendering starts.
124+ // Make sure to call `location()` by that time.
125+ let local_location = dst. join ( & * self . name ( tcx) . as_str ( ) ) ;
126+ if local_location. is_dir ( ) {
127+ return Local ;
128+ }
129+
130+ if let Some ( url) = extern_url {
131+ return to_remote ( url) ;
132+ }
133+
134+ // Failing that, see if there's an attribute specifying where to find this
135+ // external crate
136+ let did = DefId { krate : self . crate_num , index : CRATE_DEF_INDEX } ;
137+ tcx. get_attrs ( did)
138+ . lists ( sym:: doc)
139+ . filter ( |a| a. has_name ( sym:: html_root_url) )
140+ . filter_map ( |a| a. value_str ( ) )
141+ . map ( to_remote)
142+ . next ( )
143+ . unwrap_or ( Unknown ) // Well, at least we tried.
144+ }
145+
93146 crate fn keywords ( & self , tcx : TyCtxt < ' _ > ) -> ThinVec < ( DefId , Symbol ) > {
94147 let root = self . def_id ( ) ;
95148
@@ -381,7 +434,7 @@ impl Item {
381434 let relative_to = & cx. current ;
382435 if let Some ( ref fragment) = * fragment {
383436 let url = match cx. cache ( ) . extern_locations . get ( & self . def_id . krate ) {
384- Some ( & ( _ , _ , ExternalLocation :: Local ) ) => {
437+ Some ( ExternalLocation :: Local ) => {
385438 if relative_to[ 0 ] == "std" {
386439 let depth = relative_to. len ( ) - 1 ;
387440 "../" . repeat ( depth)
@@ -390,10 +443,10 @@ impl Item {
390443 format ! ( "{}std/" , "../" . repeat( depth) )
391444 }
392445 }
393- Some ( & ( _ , _ , ExternalLocation :: Remote ( ref s) ) ) => {
446+ Some ( ExternalLocation :: Remote ( ref s) ) => {
394447 format ! ( "{}/std/" , s. trim_end_matches( '/' ) )
395448 }
396- Some ( & ( _ , _ , ExternalLocation :: Unknown ) ) | None => format ! (
449+ Some ( ExternalLocation :: Unknown ) | None => format ! (
397450 "https://doc.rust-lang.org/{}/std/" ,
398451 crate :: doc_rust_lang_org_channel( ) ,
399452 ) ,
0 commit comments