Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
rustdoc_json: Fix handling of paths with no generic args.
A path without generic args, like `Reader`, currently has JSON produced
like this:
```
{"path":"Reader","id":286,"args":{"angle_bracketed":{"args":[],"constraints":[]}}}
```
Even though `types::Path::args` is `Option` and allows for "no args",
instead it gets represented as "empty args". (More like `Reader<>` than
`Reader`.)

This is due to a problem in `clean::Path::from_clean`. It only produces
`None` if the path is an empty string. This commit changes it to also
produce `None` if there are no generic args. The example above becomes:
```
{"path":"Reader","id":286,"args":null}
```
I looked at a few examples and saw this reduce the size of the JSON
output by 3-9%.

The commit also adds an assertion that non-final segments don't have any
generics; something the old code was implicitly relying on.

Note: the original sin here is that `clean::PathSegment::args` is not an
`Option`, unlike `{ast,hir}::PathSegment::args`. I want to fix that, but
it can be done separately.
  • Loading branch information
nnethercote committed Jun 21, 2025
commit 40ba7913fc229ff2d17824fadc3b7c66a931f040
19 changes: 18 additions & 1 deletion src/librustdoc/json/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,24 @@ 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()));
if final_seg.args.is_empty() {
None
} else {
Some(Box::new(final_seg.args.into_json(renderer)))
}
} else {
None // no generics on any segments because there are no segments
}
},
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/rustdoc-json/generic-args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ impl MyTrait for MyStruct {
}

//@ is "$.index[?(@.name=='my_fn1')].inner.function.sig.inputs[0][1].qualified_path.args" {\"angle_bracketed\":{\"args\":[],\"constraints\":[]}}
//@ is "$.index[?(@.name=='my_fn1')].inner.function.sig.inputs[0][1].qualified_path.self_type.resolved_path.args" {\"angle_bracketed\":{\"args\":[],\"constraints\":[]}}
//@ 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" {\"angle_bracketed\":{\"args\":[],\"constraints\":[]}}
Expand Down