Skip to content

Commit

Permalink
* Rename 'move_span' into 'local_span_to_global_span'
Browse files Browse the repository at this point in the history
* Add documentation on new arguments/functions
  • Loading branch information
GuillaumeGomez committed Aug 5, 2021
1 parent b5c27b4 commit 2a3b71a
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 17 deletions.
10 changes: 7 additions & 3 deletions src/librustdoc/clean/types.rs
Expand Up @@ -1943,14 +1943,18 @@ crate enum Variant {
crate struct Span(rustc_span::Span);

impl Span {
/// Wraps a [`rustc_span::Span`]. In case this span is the result of a macro expansion, the
/// span will be updated to point to the macro invocation instead of the macro definition.
///
/// (See rust-lang/rust#39726)
crate fn from_rustc_span(sp: rustc_span::Span) -> Self {
// Get the macro invocation instead of the definition,
// in case the span is result of a macro expansion.
// (See rust-lang/rust#39726)
Self(sp.source_callsite())
}

/// Unless you know what you're doing, use [`Self::from_rustc_span`] instead!
///
/// Contrary to [`Self::from_rustc_span`], this constructor wraps the span as is and don't
/// perform any operation on it, even if it's from a macro expansion.
crate fn wrap(sp: rustc_span::Span) -> Span {
Self(sp)
}
Expand Down
5 changes: 1 addition & 4 deletions src/librustdoc/html/format.rs
Expand Up @@ -494,10 +494,7 @@ crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<Str
if !did.is_local() && !cache.access_levels.is_public(did) && !cache.document_private {
return Err(HrefError::Private);
}
// href_with_depth_inner(did, cache, || {
// let depth = CURRENT_DEPTH.with(|l| l.get());
// "../".repeat(depth)
// })

let (fqp, shortty, mut url_parts) = match cache.paths.get(&did) {
Some(&(ref fqp, shortty)) => (fqp, shortty, {
let module_fqp = to_module_fqp(shortty, fqp);
Expand Down
70 changes: 60 additions & 10 deletions src/librustdoc/html/highlight.rs
Expand Up @@ -63,6 +63,24 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf
}
}

/// Convert the given `src` source code into HTML by adding classes for highlighting.
///
/// This code is used to render code blocks (in the documentation) as well as the source code pages.
///
/// Some explanations on the last arguments:
///
/// In case we are rendering a code block and not a source code file, `file_span_lo` value doesn't
/// matter and `context` will be `None`. To put it more simply: if `context` is `None`, the code
/// won't try to generate links to an ident definition.
///
/// More explanations about spans and how we use them here are provided in the
/// [`local_span_to_global_span`] function documentation about how it works.
///
/// As for `root_path`, it's used to know "how far" from the top of the directory we are to link
/// to either documentation pages or other source pages.
///
/// Same as `file_span_lo`: its value doesn't matter in case you are not rendering a source code
/// file.
fn write_code(
out: &mut Buffer,
src: &str,
Expand Down Expand Up @@ -135,6 +153,8 @@ impl Class {
}
}

/// In case this is an item which can be converted into a link to a definition, it'll contain
/// a "span" (a tuple representing `(lo, hi)` equivalent of `Span`).
fn get_span(self) -> Option<(u32, u32)> {
match self {
Self::Ident(sp) | Self::Self_(sp) => Some(sp),
Expand Down Expand Up @@ -166,7 +186,7 @@ impl Iterator for TokenIter<'a> {
}
}

/// Returns `None` if this is a `Class::Ident`.
/// Classifies into identifier class; returns `None` if this is a non-keyword identifier.
fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool) -> Option<Class> {
let ignore: &[&str] =
if allow_path_keywords { &["self", "Self", "super", "crate"] } else { &["self", "Self"] };
Expand All @@ -181,7 +201,20 @@ fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool)
})
}

fn move_span(file_span_lo: u32, start: u32, end: u32) -> (u32, u32) {
/// Before explaining what this function does, some global explanations on rust's `Span`:
///
/// Each source code file is stored in the source map in the compiler and has a
/// `lo` and a `hi` (lowest and highest bytes in this source map which can be seen as one huge
/// string to simplify things). So in this case, this represents the starting byte of the current
/// file. It'll be used later on to retrieve the "definition span" from the
/// `span_correspondance_map` (which is inside `context`).
///
/// This when we transform the "span" we have from reading the input into a "span" which can be
/// used as index to the `span_correspondance_map` to get the definition of this item.
///
/// So in here, `file_span_lo` is representing the "lo" byte in the global source map, and to make
/// our "span" works in there, we simply add `file_span_lo` to our values.
fn local_span_to_global_span(file_span_lo: u32, start: u32, end: u32) -> (u32, u32) {
(start + file_span_lo, end + file_span_lo)
}

Expand All @@ -199,6 +232,9 @@ struct Classifier<'a> {
}

impl<'a> Classifier<'a> {
/// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
/// file "lo" byte which we be used later on by the `span_correspondance_map`. More explanations
/// are provided in the [`local_span_to_global_span`] function documentation about how it works.
fn new(src: &str, edition: Edition, file_span_lo: u32) -> Classifier<'_> {
let tokens = TokenIter { src }.peekable();
Classifier {
Expand Down Expand Up @@ -263,7 +299,10 @@ impl<'a> Classifier<'a> {
}
}

/// Wraps the tokens iteration to ensure that the byte_pos is always correct.
/// Wraps the tokens iteration to ensure that the `byte_pos` is always correct.
///
/// It returns the token's kind, the token as a string and its byte position in the source
/// string.
fn next(&mut self) -> Option<(TokenKind, &'a str, u32)> {
if let Some((kind, text)) = self.tokens.next() {
let before = self.byte_pos;
Expand Down Expand Up @@ -306,8 +345,12 @@ impl<'a> Classifier<'a> {
}
}

/// Single step of highlighting. This will classify `token`, but maybe also
/// a couple of following ones as well.
/// Single step of highlighting. This will classify `token`, but maybe also a couple of
/// following ones as well.
///
/// `before` is the position of the given token in the `source` string and is used as "lo" byte
/// in case we want to try to generate a link for this token using the
/// `span_correspondance_map`.
fn advance(
&mut self,
token: TokenKind,
Expand Down Expand Up @@ -453,22 +496,24 @@ impl<'a> Classifier<'a> {
self.in_macro_nonterminal = false;
Class::MacroNonTerminal
}
"self" | "Self" => Class::Self_(move_span(
"self" | "Self" => Class::Self_(local_span_to_global_span(
self.file_span_lo,
before,
before + text.len() as u32,
)),
_ => Class::Ident(move_span(
_ => Class::Ident(local_span_to_global_span(
self.file_span_lo,
before,
before + text.len() as u32,
)),
},
Some(c) => c,
},
TokenKind::RawIdent | TokenKind::UnknownPrefix => {
Class::Ident(move_span(self.file_span_lo, before, before + text.len() as u32))
}
TokenKind::RawIdent | TokenKind::UnknownPrefix => Class::Ident(local_span_to_global_span(
self.file_span_lo,
before,
before + text.len() as u32,
)),
TokenKind::Lifetime { .. } => Class::Lifetime,
};
// Anything that didn't return above is the simple case where we the
Expand Down Expand Up @@ -501,8 +546,13 @@ fn exit_span(out: &mut Buffer) {
/// enter_span(Foo), string("text", None), exit_span()
/// string("text", Foo)
/// ```
///
/// The latter can be thought of as a shorthand for the former, which is more
/// flexible.
///
/// Note that if `context` is not `None` and that the given `klass` contains a `Span`, the function
/// will then try to find this `span` in the `span_correspondance_map`. If found, it'll then
/// generate a link for this element (which corresponds to where its definition is located).
fn string<T: Display>(
out: &mut Buffer,
text: T,
Expand Down
17 changes: 17 additions & 0 deletions src/librustdoc/html/render/span_map.rs
Expand Up @@ -9,12 +9,29 @@ use rustc_hir::{ExprKind, GenericParam, GenericParamKind, HirId, Mod, Node};
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;

/// This enum allows us to store two different kinds of information:
///
/// In case the `span` definition comes from the same crate, we can simply get the `span` and use
/// it as is.
///
/// Otherwise, we store the definition `DefId` and will generate a link to the documentation page
/// instead of the source code directly.
#[derive(Debug)]
crate enum LinkFromSrc {
Local(Span),
External(DefId),
}

/// This function will do at most two things:
///
/// 1. Generate a `span` correspondance map which links an item `span` to its definition `span`.
/// 2. Collect the source code files.
///
/// It returns the `krate`, the source code files and the `span` correspondance map.
///
/// Note about the `span` correspondance map: the keys are actually `(lo, hi)` of `span`s. We don't
/// need the `span` context later on, only their position, so instead of keep a whole `Span`, we
/// only keep the `lo` and `hi`.
crate fn collect_spans_and_sources(
tcx: TyCtxt<'_>,
krate: clean::Crate,
Expand Down

0 comments on commit 2a3b71a

Please sign in to comment.