Skip to content

Commit

Permalink
rustdoc: rich-text and visibility-aware formatting for constant values
Browse files Browse the repository at this point in the history
  • Loading branch information
fmease committed Aug 14, 2022
1 parent 2fbc08e commit 85c0d9e
Show file tree
Hide file tree
Showing 44 changed files with 1,636 additions and 379 deletions.
2 changes: 2 additions & 0 deletions src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,8 @@ fn build_module_items(
}

pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
// FIXME: Both branches rely on HIR pretty-printing which
// leaks private and doc(hidden) struct fields.
if let Some(did) = did.as_local() {
let hir_id = tcx.hir().local_def_id_to_hir_id(did);
rustc_hir_pretty::id_to_string(&tcx.hir(), hir_id)
Expand Down
14 changes: 7 additions & 7 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ use crate::clean::cfg::Cfg;
use crate::clean::clean_visibility;
use crate::clean::external_path;
use crate::clean::inline::{self, print_inlined_const};
use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
use crate::clean::utils::is_literal_expr;
use crate::core::DocContext;
use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType;
use crate::html::render::Context;
use crate::html::render::{constant::Renderer as ConstantRenderer, Context};
use crate::passes::collect_intra_doc_links::UrlFragment;

pub(crate) use self::FnRetTy::*;
Expand Down Expand Up @@ -2292,8 +2292,8 @@ impl Constant {
self.kind.expr(tcx)
}

pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
self.kind.value(tcx)
pub(crate) fn eval_and_render(&self, renderer: &ConstantRenderer<'_, '_>) -> Option<String> {
self.kind.eval_and_render(renderer)
}

pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
Expand All @@ -2307,16 +2307,16 @@ impl ConstantKind {
ConstantKind::TyConst { ref expr } => expr.clone(),
ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
print_const_expr(tcx, body)
super::utils::print_const_expr(tcx, body)
}
}
}

pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
pub(crate) fn eval_and_render(&self, renderer: &ConstantRenderer<'_, '_>) -> Option<String> {
match *self {
ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None,
ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
print_evaluated_const(tcx, def_id)
crate::html::render::eval_and_render_const(def_id, renderer)
}
}
}
Expand Down
70 changes: 2 additions & 68 deletions src/librustdoc/clean/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,12 @@ use rustc_data_structures::thin_vec::ThinVec;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::mir;
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
use rustc_span::symbol::{kw, sym, Symbol};
use std::fmt::Write as _;
use std::mem;

#[cfg(test)]
mod tests;

pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
let module = crate::visit_ast::RustdocVisitor::new(cx).visit();

Expand Down Expand Up @@ -238,6 +233,8 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
let mut s = if let Some(def) = def.as_local() {
print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(def.did))
} else {
// FIXME: This relies on the HIR pretty-printer which leaks private and
// doc(hidden) struct fields.
inline::print_inlined_const(cx.tcx, def.did)
};
if let Some(promoted) = promoted {
Expand All @@ -261,69 +258,6 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
}
}

pub(crate) fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<String> {
tcx.const_eval_poly(def_id).ok().and_then(|val| {
let ty = tcx.type_of(def_id);
match (val, ty.kind()) {
(_, &ty::Ref(..)) => None,
(ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
(ConstValue::Scalar(_), _) => {
let const_ = mir::ConstantKind::from_value(val, ty);
Some(print_const_with_custom_print_scalar(tcx, const_))
}
_ => None,
}
})
}

fn format_integer_with_underscore_sep(num: &str) -> String {
let num_chars: Vec<_> = num.chars().collect();
let mut num_start_index = if num_chars.get(0) == Some(&'-') { 1 } else { 0 };
let chunk_size = match num[num_start_index..].as_bytes() {
[b'0', b'b' | b'x', ..] => {
num_start_index += 2;
4
}
[b'0', b'o', ..] => {
num_start_index += 2;
let remaining_chars = num_chars.len() - num_start_index;
if remaining_chars <= 6 {
// don't add underscores to Unix permissions like 0755 or 100755
return num.to_string();
}
3
}
_ => 3,
};

num_chars[..num_start_index]
.iter()
.chain(num_chars[num_start_index..].rchunks(chunk_size).rev().intersperse(&['_']).flatten())
.collect()
}

fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: mir::ConstantKind<'_>) -> String {
// Use a slightly different format for integer types which always shows the actual value.
// For all other types, fallback to the original `pretty_print_const`.
match (ct, ct.ty().kind()) {
(mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Uint(ui)) => {
format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
}
(mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Int(i)) => {
let ty = tcx.lift(ct.ty()).unwrap();
let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
let data = int.assert_bits(size);
let sign_extended_data = size.sign_extend(data) as i128;
format!(
"{}{}",
format_integer_with_underscore_sep(&sign_extended_data.to_string()),
i.name_str()
)
}
_ => ct.to_string(),
}
}

pub(crate) fn is_literal_expr(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
if let hir::Node::Expr(expr) = tcx.hir().get(hir_id) {
if let hir::ExprKind::Lit(_) = &expr.kind {
Expand Down
41 changes: 0 additions & 41 deletions src/librustdoc/clean/utils/tests.rs

This file was deleted.

6 changes: 5 additions & 1 deletion src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,11 @@ pub(crate) fn run_global_ctxt(
impl_trait_bounds: Default::default(),
generated_synthetics: Default::default(),
auto_traits,
cache: Cache::new(access_levels, render_options.document_private),
cache: Cache::new(
access_levels,
render_options.document_private,
render_options.document_hidden,
),
inlined: FxHashSet::default(),
output_format,
render_options,
Expand Down
12 changes: 10 additions & 2 deletions src/librustdoc/formats/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ pub(crate) struct Cache {
/// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
pub(crate) document_private: bool,

/// Whether to document `#[doc(hidden)]` items.
/// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
pub(crate) document_hidden: bool,

/// Crates marked with [`#[doc(masked)]`][doc_masked].
///
/// [doc_masked]: https://doc.rust-lang.org/nightly/unstable-book/language-features/doc-masked.html
Expand Down Expand Up @@ -132,8 +136,12 @@ struct CacheBuilder<'a, 'tcx> {
}

impl Cache {
pub(crate) fn new(access_levels: AccessLevels<DefId>, document_private: bool) -> Self {
Cache { access_levels, document_private, ..Cache::default() }
pub(crate) fn new(
access_levels: AccessLevels<DefId>,
document_private: bool,
document_hidden: bool,
) -> Self {
Cache { access_levels, document_private, document_hidden, ..Cache::default() }
}

/// Populates the `Cache` with more data. The returned `Crate` will be missing some data that was
Expand Down
7 changes: 7 additions & 0 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,13 @@ pub(crate) fn href_with_root_path(
// documented on their parent's page
tcx.parent(did)
}
DefKind::Field => {
let parent_id = tcx.parent(did);
match tcx.def_kind(parent_id) {
DefKind::Variant => tcx.parent(parent_id),
_ => parent_id,
}
}
_ => did,
};
let cache = cx.cache();
Expand Down
Loading

0 comments on commit 85c0d9e

Please sign in to comment.