From 987c73158e2120ef75b4b7fc46dcd88a621106d8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 20 Jun 2022 22:32:49 +0200 Subject: [PATCH] Integrate `generate_macro_def_id_path` into `href_with_root_path` --- src/librustdoc/html/format.rs | 71 +++++++++++++++++++++++++++++++- src/librustdoc/html/highlight.rs | 69 +------------------------------ 2 files changed, 72 insertions(+), 68 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 29a58810036..67b01245ef7 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -8,14 +8,16 @@ use std::borrow::Cow; use std::cell::Cell; use std::fmt; -use std::iter; +use std::iter::{self, once}; +use rustc_ast as ast; use rustc_attr::{ConstStability, StabilityLevel}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; +use rustc_metadata::creader::{CStore, LoadedMacro}; use rustc_middle::ty; use rustc_middle::ty::DefIdTree; use rustc_middle::ty::TyCtxt; @@ -557,6 +559,71 @@ pub(crate) fn join_with_double_colon(syms: &[Symbol]) -> String { s } +/// This function is to get the external macro path because they are not in the cache used in +/// `href_with_root_path`. +fn generate_macro_def_id_path( + def_id: DefId, + cx: &Context<'_>, + root_path: Option<&str>, +) -> (String, ItemType, Vec) { + let tcx = cx.shared.tcx; + let crate_name = tcx.crate_name(def_id.krate).to_string(); + let cache = cx.cache(); + + let fqp: Vec = tcx + .def_path(def_id) + .data + .into_iter() + .filter_map(|elem| { + // extern blocks (and a few others things) have an empty name. + match elem.data.get_opt_name() { + Some(s) if !s.is_empty() => Some(s), + _ => None, + } + }) + .collect(); + let relative = fqp.iter().map(|elem| elem.to_string()); + // Check to see if it is a macro 2.0 or built-in macro. + // More information in . + let is_macro_2 = match CStore::from_tcx(tcx).load_macro_untracked(def_id, tcx.sess) { + LoadedMacro::MacroDef(def, _) => { + // If `ast_def.macro_rules` is `true`, then it's not a macro 2.0. + matches!(&def.kind, ast::ItemKind::MacroDef(ast_def) if !ast_def.macro_rules) + } + _ => false, + }; + + let mut path = if is_macro_2 { + once(crate_name.clone()).chain(relative).collect() + } else { + vec![crate_name.clone(), relative.last().unwrap()] + }; + if path.len() < 2 { + // The minimum we can have is the crate name followed by the macro name. If shorter, then + // it means that that `relative` was empty, which is an error. + panic!("macro path cannot be empty!"); + } + + if let Some(last) = path.last_mut() { + *last = format!("macro.{}.html", last); + } + + let url = match cache.extern_locations[&def_id.krate] { + ExternalLocation::Remote(ref s) => { + // `ExternalLocation::Remote` always end with a `/`. + format!("{}{}", s, path.join("/")) + } + ExternalLocation::Local => { + // `root_path` always end with a `/`. + format!("{}{}/{}", root_path.unwrap_or(""), crate_name, path.join("/")) + } + ExternalLocation::Unknown => { + panic!("crate {} not in cache when linkifying macros", crate_name) + } + }; + (url, ItemType::Macro, fqp) +} + pub(crate) fn href_with_root_path( did: DefId, cx: &Context<'_>, @@ -612,6 +679,8 @@ fn to_module_fqp(shortty: ItemType, fqp: &[Symbol]) -> &[Symbol] { ExternalLocation::Unknown => return Err(HrefError::DocumentationNotBuilt), }, ) + } else if matches!(def_kind, DefKind::Macro(_)) { + return Ok(generate_macro_def_id_path(did, cx, root_path)); } else { return Err(HrefError::NotInExternalCache); } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 11ab3a3f931..d2ef89078bf 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -5,19 +5,15 @@ //! //! Use the `render_with_highlighting` to highlight some rust code. -use crate::clean::{ExternalLocation, PrimitiveType}; +use crate::clean::PrimitiveType; use crate::html::escape::Escape; use crate::html::render::Context; use std::collections::VecDeque; use std::fmt::{Display, Write}; -use std::iter::once; -use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::DefId; use rustc_lexer::{LiteralKind, TokenKind}; -use rustc_metadata::creader::{CStore, LoadedMacro}; use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, Span, DUMMY_SP}; @@ -784,17 +780,8 @@ fn string_without_closing_tag( .map(|s| format!("{}{}", href_context.root_path, s)), LinkFromSrc::External(def_id) => { format::href_with_root_path(*def_id, context, Some(href_context.root_path)) - .map(|(url, _, _)| url) - .or_else(|e| { - if e == format::HrefError::NotInExternalCache - && matches!(klass, Class::Macro(_)) - { - Ok(generate_macro_def_id_path(href_context, *def_id)) - } else { - Err(e) - } - }) .ok() + .map(|(url, _, _)| url) } LinkFromSrc::Primitive(prim) => format::href_with_root_path( PrimitiveType::primitive_locations(context.tcx())[prim], @@ -814,57 +801,5 @@ fn string_without_closing_tag( Some("") } -/// This function is to get the external macro path because they are not in the cache used in -/// `href_with_root_path`. -fn generate_macro_def_id_path(href_context: &HrefContext<'_, '_, '_>, def_id: DefId) -> String { - let tcx = href_context.context.shared.tcx; - let crate_name = tcx.crate_name(def_id.krate).to_string(); - let cache = href_context.context.cache(); - - let relative = tcx.def_path(def_id).data.into_iter().filter_map(|elem| { - // extern blocks have an empty name - let s = elem.data.to_string(); - if !s.is_empty() { Some(s) } else { None } - }); - // Check to see if it is a macro 2.0 or built-in macro. - // More information in . - let is_macro_2 = match CStore::from_tcx(tcx).load_macro_untracked(def_id, tcx.sess) { - LoadedMacro::MacroDef(def, _) => { - // If `ast_def.macro_rules` is `true`, then it's not a macro 2.0. - matches!(&def.kind, ast::ItemKind::MacroDef(ast_def) if !ast_def.macro_rules) - } - _ => false, - }; - - let mut path = if is_macro_2 { - once(crate_name.clone()).chain(relative).collect() - } else { - vec![crate_name.clone(), relative.last().unwrap()] - }; - if path.len() < 2 { - // The minimum we can have is the crate name followed by the macro name. If shorter, then - // it means that that `relative` was empty, which is an error. - panic!("macro path cannot be empty!"); - } - - if let Some(last) = path.last_mut() { - *last = format!("macro.{}.html", last); - } - - match cache.extern_locations[&def_id.krate] { - ExternalLocation::Remote(ref s) => { - // `ExternalLocation::Remote` always end with a `/`. - format!("{}{}", s, path.join("/")) - } - ExternalLocation::Local => { - // `href_context.root_path` always end with a `/`. - format!("{}{}/{}", href_context.root_path, crate_name, path.join("/")) - } - ExternalLocation::Unknown => { - panic!("crate {} not in cache when linkifying macros", crate_name) - } - } -} - #[cfg(test)] mod tests; -- GitLab