}
}
-crate fn href(did: DefId, cx: &Context<'_>) -> Option<(String, ItemType, Vec<String>)> {
+// Possible errors when computing href link source for a `DefId`
+crate enum HrefError {
+ // `DefId` is in an unknown location. This seems to happen when building without dependencies
+ // but a trait from a dependency is still visible
+ UnknownLocation,
+ // Unavailable because private
+ Unavailable,
+ // Not in external cache, href link should be in same page
+ NotInExternalCache,
+}
+
+crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<String>), HrefError> {
let cache = &cx.cache();
let relative_to = &cx.current;
fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
}
if !did.is_local() && !cache.access_levels.is_public(did) && !cache.document_private {
- return None;
+ return Err(HrefError::Unavailable);
}
let (fqp, shortty, mut url_parts) = match cache.paths.get(&did) {
href_relative_parts(module_fqp, relative_to)
}),
None => {
- let &(ref fqp, shortty) = cache.external_paths.get(&did)?;
- let module_fqp = to_module_fqp(shortty, fqp);
- (
- fqp,
- shortty,
- match cache.extern_locations[&did.krate] {
- ExternalLocation::Remote(ref s) => {
- let s = s.trim_end_matches('/');
- let mut s = vec![&s[..]];
- s.extend(module_fqp[..].iter().map(String::as_str));
- s
- }
- ExternalLocation::Local => href_relative_parts(module_fqp, relative_to),
- ExternalLocation::Unknown => return None,
- },
- )
+ if let Some(&(ref fqp, shortty)) = cache.external_paths.get(&did) {
+ let module_fqp = to_module_fqp(shortty, fqp);
+ (
+ fqp,
+ shortty,
+ match cache.extern_locations[&did.krate] {
+ ExternalLocation::Remote(ref s) => {
+ let s = s.trim_end_matches('/');
+ let mut s = vec![&s[..]];
+ s.extend(module_fqp[..].iter().map(String::as_str));
+ s
+ }
+ ExternalLocation::Local => href_relative_parts(module_fqp, relative_to),
+ ExternalLocation::Unknown => return Err(HrefError::UnknownLocation),
+ },
+ )
+ } else {
+ return Err(HrefError::NotInExternalCache);
+ }
}
};
let last = &fqp.last().unwrap()[..];
url_parts.push(&filename);
}
}
- Some((url_parts.join("/"), shortty, fqp.to_vec()))
+ Ok((url_parts.join("/"), shortty, fqp.to_vec()))
}
/// Both paths should only be modules.
write!(w, "{}{:#}", &last.name, last.args.print(cx))?;
} else {
let path = if use_absolute {
- if let Some((_, _, fqp)) = href(did, cx) {
+ if let Ok((_, _, fqp)) = href(did, cx) {
format!(
"{}::{}",
fqp[..fqp.len() - 1].join("::"),
) -> impl fmt::Display + 'a {
let parts = href(did.into(), cx);
display_fn(move |f| {
- if let Some((url, short_ty, fqp)) = parts {
+ if let Ok((url, short_ty, fqp)) = parts {
write!(
f,
r#"<a class="{}" href="{}" title="{} {}">{}</a>"#,
// look at).
box clean::ResolvedPath { did, .. } => {
match href(did.into(), cx) {
- Some((ref url, _, ref path)) if !f.alternate() => {
+ Ok((ref url, _, ref path)) if !f.alternate() => {
write!(
f,
"<a class=\"type\" href=\"{url}#{shortty}.{name}\" \
use crate::html::escape::Escape;
use crate::html::format::{
href, print_abi_with_space, print_constness_with_space, print_default_space,
- print_generic_bounds, print_where_clause, Buffer, PrintWithSpace,
+ print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace,
};
use crate::html::markdown::{Markdown, MarkdownHtml, MarkdownSummaryLine};
) {
let name = meth.name.as_ref().unwrap();
let href = match link {
- AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
- AssocItemLink::Anchor(None) => format!("#{}.{}", meth.type_(), name),
+ AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)),
+ AssocItemLink::Anchor(None) => Some(format!("#{}.{}", meth.type_(), name)),
AssocItemLink::GotoSource(did, provided_methods) => {
// We're creating a link from an impl-item to the corresponding
// trait-item and need to map the anchored type accordingly.
ItemType::TyMethod
};
- href(did.expect_def_id(), cx)
- .map(|p| format!("{}#{}.{}", p.0, ty, name))
- .unwrap_or_else(|| format!("#{}.{}", ty, name))
+ match href(did.expect_def_id(), cx) {
+ Ok(p) => Some(format!("{}#{}.{}", p.0, ty, name)),
+ Err(HrefError::UnknownLocation) => None,
+ Err(_) => Some(format!("#{}.{}", ty, name)),
+ }
}
};
let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string();
w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len());
write!(
w,
- "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\
+ "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a {href} class=\"fnname\">{name}</a>\
{generics}{decl}{notable_traits}{where_clause}",
indent = indent_str,
vis = vis,
unsafety = unsafety,
defaultness = defaultness,
abi = abi,
- href = href,
+ href = href.map(|href| format!("href=\"{}\"", href)).unwrap_or_else(|| "".to_string()),
name = name,
generics = g.print(cx),
decl = d.full_print(header_len, indent, header.asyncness, cx),