Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 8 pull requests #98381

Closed
wants to merge 24 commits into from
Closed
Changes from 7 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a336686
Fix trait object reborrow suggestion
compiler-errors Jun 20, 2022
448e00b
Note concrete type being coerced into object
compiler-errors Jun 20, 2022
1e7ab0b
point at private fields in struct literal
TaKO8Ki Jun 20, 2022
3f12fa7
Add support for macro in "jump to def" feature
GuillaumeGomez Nov 26, 2021
dda980d
Rename ContextInfo into HrefContext
GuillaumeGomez Jun 18, 2022
f001795
don't alloc error string if no error emitted
klensy Jun 20, 2022
810254b
Improve code readability and documentation
GuillaumeGomez Jun 18, 2022
f4db07e
Add test for macro support in "jump to def" feature
GuillaumeGomez Nov 26, 2021
987c731
Integrate `generate_macro_def_id_path` into `href_with_root_path`
GuillaumeGomez Jun 20, 2022
beb2f36
Fix panic by checking if `CStore` has the crate data we want before a…
GuillaumeGomez Jun 20, 2022
b37a05b
rustdoc: optimize loading of source sidebar
jsha Jun 20, 2022
e900a35
Give name if anonymous region appears in impl signature
compiler-errors Jun 21, 2022
f924e74
Provide a segment res in more cases
compiler-errors Jun 20, 2022
a0eba66
[RFC 2011] Optimize non-consuming operators
c410-f3r Jun 21, 2022
f847261
stop pointing at definitions of missing fields
TaKO8Ki Jun 22, 2022
eb86daa
add "was" to pluralize macro and use it
TaKO8Ki Jun 22, 2022
ef5ff2f
Rollup merge of #91264 - GuillaumeGomez:macro-jump-to-def, r=jsha
Dylan-DPC Jun 22, 2022
c26b9dd
Rollup merge of #98184 - compiler-errors:elided-lifetime-in-impl-nll,…
Dylan-DPC Jun 22, 2022
9ee8708
Rollup merge of #98269 - compiler-errors:provide-more-segment-res, r=…
Dylan-DPC Jun 22, 2022
4a72e16
Rollup merge of #98277 - compiler-errors:issue-93596, r=estebank
Dylan-DPC Jun 22, 2022
082289e
Rollup merge of #98283 - TaKO8Ki:point-at-private-fields-in-struct-li…
Dylan-DPC Jun 22, 2022
74abe7c
Rollup merge of #98305 - klensy:no-err-alloc, r=compiler-errors
Dylan-DPC Jun 22, 2022
3a97aba
Rollup merge of #98310 - jsha:defer-source-sidebar, r=GuillaumeGomez
Dylan-DPC Jun 22, 2022
77732a5
Rollup merge of #98337 - c410-f3r:assert-compiler, r=oli-obk
Dylan-DPC Jun 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/rustc_metadata/src/creader.rs
Original file line number Diff line number Diff line change
@@ -133,6 +133,10 @@ impl CStore {
CrateNum::new(self.metas.len() - 1)
}

pub fn has_crate_data(&self, cnum: CrateNum) -> bool {
self.metas[cnum].is_some()
}

pub(crate) fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> {
let cdata = self.metas[cnum]
.as_ref()
80 changes: 79 additions & 1 deletion src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
@@ -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;
@@ -519,6 +521,7 @@ impl clean::GenericArgs {
}

// Possible errors when computing href link source for a `DefId`
#[derive(PartialEq, Eq)]
pub(crate) enum HrefError {
/// This item is known to rustdoc, but from a crate that does not have documentation generated.
///
@@ -556,6 +559,79 @@ 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>,
) -> Result<(String, ItemType, Vec<Symbol>), HrefError> {
let tcx = cx.shared.tcx;
let crate_name = tcx.crate_name(def_id.krate).to_string();
let cache = cx.cache();

let fqp: Vec<Symbol> = 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());
let cstore = CStore::from_tcx(tcx);
// We need this to prevent a `panic` when this function is used from intra doc links...
if !cstore.has_crate_data(def_id.krate) {
debug!("No data for crate {}", crate_name);
return Err(HrefError::NotInExternalCache);
}
// Check to see if it is a macro 2.0 or built-in macro.
// More information in <https://rust-lang.github.io/rfcs/1584-macros.html>.
let is_macro_2 = match cstore.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.
debug!("macro path cannot be empty!");
return Err(HrefError::NotInExternalCache);
}

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 => {
debug!("crate {} not in cache when linkifying macros", crate_name);
return Err(HrefError::NotInExternalCache);
}
};
Ok((url, ItemType::Macro, fqp))
}

pub(crate) fn href_with_root_path(
did: DefId,
cx: &Context<'_>,
@@ -611,6 +687,8 @@ pub(crate) fn href_with_root_path(
ExternalLocation::Unknown => return Err(HrefError::DocumentationNotBuilt),
},
)
} else if matches!(def_kind, DefKind::Macro(_)) {
return generate_macro_def_id_path(did, cx, root_path);
} else {
return Err(HrefError::NotInExternalCache);
}
115 changes: 83 additions & 32 deletions src/librustdoc/html/highlight.rs
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ use super::format::{self, Buffer};
use super::render::LinkFromSrc;

/// This type is needed in case we want to render links on items to allow to go to their definition.
pub(crate) struct ContextInfo<'a, 'b, 'c> {
pub(crate) struct HrefContext<'a, 'b, 'c> {
pub(crate) context: &'a Context<'b>,
/// This span contains the current file we're going through.
pub(crate) file_span: Span,
@@ -44,7 +44,7 @@ pub(crate) fn render_with_highlighting(
tooltip: Option<(Option<Edition>, &str)>,
edition: Edition,
extra_content: Option<Buffer>,
context_info: Option<ContextInfo<'_, '_, '_>>,
href_context: Option<HrefContext<'_, '_, '_>>,
decoration_info: Option<DecorationInfo>,
) {
debug!("highlighting: ================\n{}\n==============", src);
@@ -62,7 +62,7 @@ pub(crate) fn render_with_highlighting(
}

write_header(out, class, extra_content);
write_code(out, src, edition, context_info, decoration_info);
write_code(out, src, edition, href_context, decoration_info);
write_footer(out, playground_button);
}

@@ -85,31 +85,36 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf
///
/// Some explanations on the last arguments:
///
/// In case we are rendering a code block and not a source code file, `context_info` will be `None`.
/// To put it more simply: if `context_info` is `None`, the code won't try to generate links to an
/// In case we are rendering a code block and not a source code file, `href_context` will be `None`.
/// To put it more simply: if `href_context` is `None`, the code won't try to generate links to an
/// item definition.
///
/// More explanations about spans and how we use them here are provided in the
fn write_code(
out: &mut Buffer,
src: &str,
edition: Edition,
context_info: Option<ContextInfo<'_, '_, '_>>,
href_context: Option<HrefContext<'_, '_, '_>>,
decoration_info: Option<DecorationInfo>,
) {
// This replace allows to fix how the code source with DOS backline characters is displayed.
let src = src.replace("\r\n", "\n");
let mut closing_tags: Vec<&'static str> = Vec::new();
Classifier::new(
&src,
edition,
context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
decoration_info,
)
.highlight(&mut |highlight| {
match highlight {
Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
Highlight::EnterSpan { class } => enter_span(out, class),
Highlight::ExitSpan => exit_span(out),
Highlight::Token { text, class } => string(out, Escape(text), class, &href_context),
Highlight::EnterSpan { class } => {
closing_tags.push(enter_span(out, class, &href_context))
}
Highlight::ExitSpan => {
exit_span(out, closing_tags.pop().expect("ExitSpan without EnterSpan"))
}
};
});
}
@@ -129,7 +134,7 @@ enum Class {
RefKeyWord,
Self_(Span),
Op,
Macro,
Macro(Span),
MacroNonTerminal,
String,
Number,
@@ -153,7 +158,7 @@ impl Class {
Class::RefKeyWord => "kw-2",
Class::Self_(_) => "self",
Class::Op => "op",
Class::Macro => "macro",
Class::Macro(_) => "macro",
Class::MacroNonTerminal => "macro-nonterminal",
Class::String => "string",
Class::Number => "number",
@@ -171,8 +176,22 @@ impl Class {
/// a "span" (a tuple representing `(lo, hi)` equivalent of `Span`).
fn get_span(self) -> Option<Span> {
match self {
Self::Ident(sp) | Self::Self_(sp) => Some(sp),
_ => None,
Self::Ident(sp) | Self::Self_(sp) | Self::Macro(sp) => Some(sp),
Self::Comment
| Self::DocComment
| Self::Attribute
| Self::KeyWord
| Self::RefKeyWord
| Self::Op
| Self::MacroNonTerminal
| Self::String
| Self::Number
| Self::Bool
| Self::Lifetime
| Self::PreludeTy
| Self::PreludeVal
| Self::QuestionMark
| Self::Decoration(_) => None,
}
}
}
@@ -611,7 +630,7 @@ impl<'a> Classifier<'a> {
},
TokenKind::Ident | TokenKind::RawIdent if lookahead == Some(TokenKind::Bang) => {
self.in_macro = true;
sink(Highlight::EnterSpan { class: Class::Macro });
sink(Highlight::EnterSpan { class: Class::Macro(self.new_span(before, text)) });
sink(Highlight::Token { text, class: None });
return;
}
@@ -658,13 +677,20 @@ impl<'a> Classifier<'a> {

/// Called when we start processing a span of text that should be highlighted.
/// The `Class` argument specifies how it should be highlighted.
fn enter_span(out: &mut Buffer, klass: Class) {
write!(out, "<span class=\"{}\">", klass.as_html());
fn enter_span(
out: &mut Buffer,
klass: Class,
href_context: &Option<HrefContext<'_, '_, '_>>,
) -> &'static str {
string_without_closing_tag(out, "", Some(klass), href_context).expect(
"internal error: enter_span was called with Some(klass) but did not return a \
closing HTML tag",
)
}

/// Called at the end of a span of highlighted text.
fn exit_span(out: &mut Buffer) {
out.write_str("</span>");
fn exit_span(out: &mut Buffer, closing_tag: &str) {
out.write_str(closing_tag);
}

/// Called for a span of text. If the text should be highlighted differently
@@ -687,15 +713,39 @@ fn string<T: Display>(
out: &mut Buffer,
text: T,
klass: Option<Class>,
context_info: &Option<ContextInfo<'_, '_, '_>>,
href_context: &Option<HrefContext<'_, '_, '_>>,
) {
if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context) {
out.write_str(closing_tag);
}
}

/// This function writes `text` into `out` with some modifications depending on `klass`:
///
/// * If `klass` is `None`, `text` is written into `out` with no modification.
/// * If `klass` is `Some` but `klass.get_span()` is `None`, it writes the text wrapped in a
/// `<span>` with the provided `klass`.
/// * If `klass` is `Some` and has a [`rustc_span::Span`], it then tries to generate a link (`<a>`
/// element) by retrieving the link information from the `span_correspondance_map` that was filled
/// in `span_map.rs::collect_spans_and_sources`. If it cannot retrieve the information, then it's
/// the same as the second point (`klass` is `Some` but doesn't have a [`rustc_span::Span`]).
fn string_without_closing_tag<T: Display>(
out: &mut Buffer,
text: T,
klass: Option<Class>,
href_context: &Option<HrefContext<'_, '_, '_>>,
) -> Option<&'static str> {
let Some(klass) = klass
else { return write!(out, "{}", text) };
else {
write!(out, "{}", text);
return None;
};
let Some(def_span) = klass.get_span()
else {
write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text);
return;
write!(out, "<span class=\"{}\">{}", klass.as_html(), text);
return Some("</span>");
};

let mut text_s = text.to_string();
if text_s.contains("::") {
text_s = text_s.split("::").intersperse("::").fold(String::new(), |mut path, t| {
@@ -715,10 +765,10 @@ fn string<T: Display>(
path
});
}
if let Some(context_info) = context_info {
if let Some(href_context) = href_context {
if let Some(href) =
context_info.context.shared.span_correspondance_map.get(&def_span).and_then(|href| {
let context = context_info.context;
href_context.context.shared.span_correspondance_map.get(&def_span).and_then(|href| {
let context = href_context.context;
// FIXME: later on, it'd be nice to provide two links (if possible) for all items:
// one to the documentation page and one to the source definition.
// FIXME: currently, external items only generate a link to their documentation,
@@ -727,27 +777,28 @@ fn string<T: Display>(
match href {
LinkFromSrc::Local(span) => context
.href_from_span(*span, true)
.map(|s| format!("{}{}", context_info.root_path, s)),
.map(|s| format!("{}{}", href_context.root_path, s)),
LinkFromSrc::External(def_id) => {
format::href_with_root_path(*def_id, context, Some(context_info.root_path))
format::href_with_root_path(*def_id, context, Some(href_context.root_path))
.ok()
.map(|(url, _, _)| url)
}
LinkFromSrc::Primitive(prim) => format::href_with_root_path(
PrimitiveType::primitive_locations(context.tcx())[prim],
context,
Some(context_info.root_path),
Some(href_context.root_path),
)
.ok()
.map(|(url, _, _)| url),
}
})
{
write!(out, "<a class=\"{}\" href=\"{}\">{}</a>", klass.as_html(), href, text_s);
return;
write!(out, "<a class=\"{}\" href=\"{}\">{}", klass.as_html(), href, text_s);
return Some("</a>");
}
}
write!(out, "<span class=\"{}\">{}</span>", klass.as_html(), text_s);
write!(out, "<span class=\"{}\">{}", klass.as_html(), text_s);
Some("</span>")
}

#[cfg(test)]
Loading