Skip to content
Merged
Changes from all commits
Commits
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
26 changes: 21 additions & 5 deletions src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
@@ -169,10 +169,13 @@ pub(crate) fn from_deprecation(deprecation: attrs::Deprecation) -> Deprecation {
Deprecation { since, note: note.map(|s| s.to_string()) }
}

impl FromClean<clean::GenericArgs> for GenericArgs {
impl FromClean<clean::GenericArgs> for Option<Box<GenericArgs>> {
fn from_clean(args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self {
use clean::GenericArgs::*;
match args {
if args.is_empty() {
return None;
}
Some(Box::new(match args {
AngleBracketed { args, constraints } => GenericArgs::AngleBracketed {
args: args.into_json(renderer),
constraints: constraints.into_json(renderer),
@@ -182,7 +185,7 @@ impl FromClean<clean::GenericArgs> for GenericArgs {
output: output.as_ref().map(|a| a.as_ref().into_json(renderer)),
},
ReturnTypeNotation => GenericArgs::ReturnTypeNotation,
}
}))
}
}

@@ -579,7 +582,20 @@ impl FromClean<clean::Path> for Path {
Path {
path: path.whole_name(),
id: renderer.id_from_item_default(path.def_id().into()),
args: path.segments.last().map(|args| Box::new(args.args.into_json(renderer))),
args: {
if let Some((final_seg, rest_segs)) = path.segments.split_last() {
// In general, `clean::Path` can hold things like
// `std::vec::Vec::<u32>::new`, where generic args appear
// in a middle segment. But for the places where `Path` is
// used by rustdoc-json-types, generic args can only be
// used in the final segment, e.g. `std::vec::Vec<u32>`. So
// check that the non-final segments have no generic args.
assert!(rest_segs.iter().all(|seg| seg.args.is_empty()));
final_seg.args.into_json(renderer)
} else {
None // no generics on any segments because there are no segments
}
},
}
}
}
@@ -590,7 +606,7 @@ impl FromClean<clean::QPathData> for Type {

Self::QualifiedPath {
name: assoc.name.to_string(),
args: Box::new(assoc.args.into_json(renderer)),
args: assoc.args.into_json(renderer),
self_type: Box::new(self_type.into_json(renderer)),
trait_: trait_.as_ref().map(|trait_| trait_.into_json(renderer)),
}
30 changes: 30 additions & 0 deletions src/librustdoc/json/mod.rs
Original file line number Diff line number Diff line change
@@ -377,3 +377,33 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
}
}
}

// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
//
// These assertions are here, not in `src/rustdoc-json-types/lib.rs` where the types are defined,
// because we have access to `static_assert_size` here.
#[cfg(target_pointer_width = "64")]
mod size_asserts {
use rustc_data_structures::static_assert_size;

use super::types::*;
// tidy-alphabetical-start
static_assert_size!(AssocItemConstraint, 112);
static_assert_size!(Crate, 184);
static_assert_size!(ExternalCrate, 48);
static_assert_size!(FunctionPointer, 168);
static_assert_size!(GenericArg, 80);
static_assert_size!(GenericArgs, 104);
static_assert_size!(GenericBound, 72);
static_assert_size!(GenericParamDef, 136);
static_assert_size!(Impl, 304);
// `Item` contains a `PathBuf`, which is different sizes on different OSes.
static_assert_size!(Item, 528 + size_of::<std::path::PathBuf>());
static_assert_size!(ItemSummary, 32);
static_assert_size!(PolyTrait, 64);
static_assert_size!(PreciseCapturingArg, 32);
static_assert_size!(TargetFeature, 80);
static_assert_size!(Type, 80);
static_assert_size!(WherePredicate, 160);
// tidy-alphabetical-end
}
14 changes: 7 additions & 7 deletions src/rustdoc-json-types/lib.rs
Original file line number Diff line number Diff line change
@@ -37,8 +37,8 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
// will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line
// are deliberately not in a doc comment, because they need not be in public docs.)
//
// Latest feature: Pretty printing of cold attributes changed
pub const FORMAT_VERSION: u32 = 50;
// Latest feature: improve handling of generic args
pub const FORMAT_VERSION: u32 = 51;

/// The root of the emitted JSON blob.
///
@@ -277,8 +277,8 @@ pub struct PolyTrait {
/// A set of generic arguments provided to a path segment, e.g.
///
/// ```text
/// std::option::Option::<u32>::None
/// ^^^^^
/// std::option::Option<u32>
/// ^^^^^
/// ```
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
@@ -331,7 +331,7 @@ pub enum GenericArg {
Const(Constant),
/// A generic argument that's explicitly set to be inferred.
/// ```text
/// std::vec::Vec::<_>::new()
/// std::vec::Vec::<_>
/// ^
/// ```
Infer,
@@ -362,7 +362,7 @@ pub struct AssocItemConstraint {
/// The name of the associated type/constant.
pub name: String,
/// Arguments provided to the associated type/constant.
pub args: GenericArgs,
pub args: Option<Box<GenericArgs>>,
/// The kind of bound applied to the associated type/constant.
pub binding: AssocItemConstraintKind,
}
@@ -1118,7 +1118,7 @@ pub enum Type {
/// <core::slice::IterMut<'static, u32> as BetterIterator>::Item<'static>
/// // ^^^^^^^^^
/// ```
args: Box<GenericArgs>,
args: Option<Box<GenericArgs>>,
/// The type with which this type is associated.
///
/// ```ignore (incomplete expression)
13 changes: 6 additions & 7 deletions src/tools/jsondoclint/src/validator.rs
Original file line number Diff line number Diff line change
@@ -271,7 +271,7 @@ impl<'a> Validator<'a> {
Type::RawPointer { is_mutable: _, type_ } => self.check_type(&**type_),
Type::BorrowedRef { lifetime: _, is_mutable: _, type_ } => self.check_type(&**type_),
Type::QualifiedPath { name: _, args, self_type, trait_ } => {
self.check_generic_args(&**args);
self.check_opt_generic_args(&args);
self.check_type(&**self_type);
if let Some(trait_) = trait_ {
self.check_path(trait_, PathKind::Trait);
@@ -309,13 +309,12 @@ impl<'a> Validator<'a> {
self.fail(&x.id, ErrorKind::Custom(format!("No entry in '$.paths' for {x:?}")));
}

if let Some(args) = &x.args {
self.check_generic_args(&**args);
}
self.check_opt_generic_args(&x.args);
}

fn check_generic_args(&mut self, x: &'a GenericArgs) {
match x {
fn check_opt_generic_args(&mut self, x: &'a Option<Box<GenericArgs>>) {
let Some(x) = x else { return };
match &**x {
GenericArgs::AngleBracketed { args, constraints } => {
args.iter().for_each(|arg| self.check_generic_arg(arg));
constraints.iter().for_each(|bind| self.check_assoc_item_constraint(bind));
@@ -355,7 +354,7 @@ impl<'a> Validator<'a> {
}

fn check_assoc_item_constraint(&mut self, bind: &'a AssocItemConstraint) {
self.check_generic_args(&bind.args);
self.check_opt_generic_args(&bind.args);
match &bind.binding {
AssocItemConstraintKind::Equality(term) => self.check_term(term),
AssocItemConstraintKind::Constraint(bounds) => {
20 changes: 20 additions & 0 deletions tests/rustdoc-json/generic-args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
pub struct MyStruct(u32);

pub trait MyTrait {
type MyType;
fn my_fn(&self);
}

impl MyTrait for MyStruct {
type MyType = u32;
fn my_fn(&self) {}
}

//@ is "$.index[?(@.name=='my_fn1')].inner.function.sig.inputs[0][1].qualified_path.args" null
//@ is "$.index[?(@.name=='my_fn1')].inner.function.sig.inputs[0][1].qualified_path.self_type.resolved_path.args" null
pub fn my_fn1(_: <MyStruct as MyTrait>::MyType) {}

//@ is "$.index[?(@.name=='my_fn2')].inner.function.sig.inputs[0][1].dyn_trait.traits[0].trait.args.angle_bracketed.constraints[0].args" null
pub fn my_fn2(_: IntoIterator<Item = MyStruct, IntoIter = impl Clone>) {}

fn main() {}