about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNicholas Nethercote <n.nethercote@gmail.com>2025-06-14 20:14:51 +1000
committerNicholas Nethercote <n.nethercote@gmail.com>2025-06-21 13:50:52 +1000
commit40ba7913fc229ff2d17824fadc3b7c66a931f040 (patch)
tree8fe518b2824aa9bf1767213567fbe43a80db500f
parent18d742bda07d6f5d047c249cdd533c0e462b3298 (diff)
downloadrust-40ba7913fc229ff2d17824fadc3b7c66a931f040.tar.gz
rust-40ba7913fc229ff2d17824fadc3b7c66a931f040.zip
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.
-rw-r--r--src/librustdoc/json/conversions.rs19
-rw-r--r--tests/rustdoc-json/generic-args.rs2
2 files changed, 19 insertions, 2 deletions
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 8b4be107ace..4719bd5d118 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -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
+                }
+            },
         }
     }
 }
diff --git a/tests/rustdoc-json/generic-args.rs b/tests/rustdoc-json/generic-args.rs
index e48c3329f56..e87c1e62304 100644
--- a/tests/rustdoc-json/generic-args.rs
+++ b/tests/rustdoc-json/generic-args.rs
@@ -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\":[]}}