Description
I tried this code:
mod inner {
pub struct Foo {};
}
mod other {
struct Foo;
}
pub use inner::*;
// Adding either of the following two lines
// would shadow `inner::Foo` and
// hide the name `Foo` from the public API.
//
// (1)
// struct Foo;
//
// (2)
// use other::Foo;
I expected to see this happen: when either line (1)
or (2)
is added, rustdoc JSON files should offer some way to detect that the name Foo
is no longer part of the crate's public API.
Instead, this happened:
- With default settings, rustdoc generates identical JSON regardless of whether either or none of
(1)
or(2)
is included. - With
--document-private-items
and--document-hidden-items
, rustdoc generates identical JSON whether or not(2)
is included.
Just like using a private type in (1)
, the same problem can be caused by using a #[doc(hidden)]
public type, which will also not be emitted in rustdoc JSON unless --document-hidden-items
is set.
This means that shadowing glob re-exported items is in general currently impossible to reliably detect via rustdoc JSON, even with --document-private-items
and --document-hidden-items
. As a result, cargo-semver-checks
cannot detect breaking changes caused by such shadowing, which have happened in real life: around a year ago, the opencl3 crate seems to have suffered a regression when a large number of its items were accidentally shadowed.
Relatedly, in #111336 I'm arguing that such shadowing should trigger a lint since it's essentially never what one wants: anything it can productively accomplish can be better accomplished in another way.
I plan to publish a blog post with more details about this in a few hours, it will be available at the following link: https://predr.ag/blog/breaking-semver-in-rust-by-adding-private-type-or-import/
Meta
rustc --version --verbose
:
rustc 1.71.0-nightly (39c6804b9 2023-04-19)
binary: rustc
commit-hash: 39c6804b92aa202369e402525cee329556bc1db0
commit-date: 2023-04-19
host: x86_64-unknown-linux-gnu
release: 1.71.0-nightly
LLVM version: 16.0.2
That version of rustc emits rustdoc JSON format version v24.
Possible solution
One option I thought of would be to tweak the rustdoc format to include a list of shadowed names in glob re-exports. This would allow proper name resolution in all cases, and without requiring --document-private-items
and --document-hidden-items
to be set.
Another option would be to include non-pub
imports when --document-private-items
is set. This only allows proper name resolution in rustdoc JSON generated with both --document-private-items
and --document-hidden-items
set.
Perhaps there are other options as well.
Personally, I'd prefer the former option over the latter, since it seems reasonable to expect that rustdoc JSON shouldn't require flags that document explicitly non-public-API components in order to fully describe the public API.