-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix dead link for method in trait of blanket impl from third party crate #86662
fix dead link for method in trait of blanket impl from third party crate #86662
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to find a test for the other crate before merging this; I'll try to do that this afternoon. I don't yet understand why your fix works.
@@ -456,15 +456,26 @@ impl clean::GenericArgs { | |||
} | |||
} | |||
|
|||
crate fn href(did: DefId, cx: &Context<'_>) -> Option<(String, ItemType, Vec<String>)> { | |||
// Possible errors when computing href link source for a `DefId` | |||
crate enum HrefError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add the MCVE from the issue as a test? I'll review this in the meantime and see if I understand it better now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not the right fix, see below.
NotInExternalCache, | ||
} | ||
|
||
crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<String>), HrefError> { | ||
let cache = &cx.cache(); | ||
let relative_to = &cx.current; | ||
fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] { | ||
if shortty == ItemType::Module { &fqp[..] } else { &fqp[..fqp.len() - 1] } | ||
} | ||
|
||
if !did.is_local() && !cache.access_levels.is_public(did) && !cache.document_private { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, !is_local
looks correct to me, but for a non-trivial reason - the strip_private
pass should get rid of private local items before they ever get here. Can you change this to an assert instead?
if !did.is_local() && !cache.access_levels.is_public(did) && !cache.document_private { | |
if did.is_local() { | |
// Private items should have already been stripped. | |
assert!(cache.access_levels.is_public(did) || cache.document_private); | |
} | |
if !cache.access_levels.is_public(did) && !cache.document_private { |
(I know this is unrelated to your change - I can make a separate PR for this if you like.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
adding this assert made the following tests fail:
failures:
[rustdoc] rustdoc/all.rs
[rustdoc] rustdoc/async-fn.rs
[rustdoc] rustdoc/blanket-reexport-item.rs
[rustdoc] rustdoc/impl-trait-alias.rs
[rustdoc] rustdoc/inline_cross/renamed-via-module.rs
[rustdoc] rustdoc/inline_local/glob-private-no-defaults.rs
[rustdoc] rustdoc/inline_local/glob-private.rs
[rustdoc] rustdoc/inline_local/issue-28537.rs
[rustdoc] rustdoc/inline_local/issue-32343.rs
[rustdoc] rustdoc/inline_local/trait-vis.rs
[rustdoc] rustdoc/intra-doc/cross-crate/hidden.rs
[rustdoc] rustdoc/issue-34473.rs
[rustdoc] rustdoc/issue-35488.rs
[rustdoc] rustdoc/issue-46767.rs
[rustdoc] rustdoc/namespaces.rs
[rustdoc] rustdoc/redirect-map.rs
[rustdoc] rustdoc/redirect-rename.rs
[rustdoc] rustdoc/redirect.rs
[rustdoc] rustdoc/search-index.rs
[rustdoc] rustdoc/struct-arg-pattern.rs
[rustdoc] rustdoc/synthetic_auto/complex.rs
[rustdoc] rustdoc/synthetic_auto/project.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahhhh of course it did :( I'll open an issue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I was just confused: the proper assert is
assert!(cache.access_levels.is_public(did) || cache.document_private || cache.paths.get(&did).is_none(), "{:?}", did);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, there was a bug after all: #87048
src/librustdoc/html/render/mod.rs
Outdated
match href(did.expect_real(), cx) { | ||
Ok(p) => Some(format!("{}#{}.{}", p.0, ty, name)), | ||
Err(HrefError::UnknownLocation) => None, | ||
Err(_) => Some(format!("#{}.{}", ty, name)), | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not look like the right fix. I expect if you change cargo doc --no-deps
to cargo doc
you'll still run into the same issue (you can test with cargo deadlinks --dir target/doc
).
The proper fix is probably to use #tymethod
for external methods and #method
for local ones? Something about the if on line 881 looks wrong, I'm not sure exactly what.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried building docs with and without dependencies for serde-encrypt
, no deadlinks on vzip
.
Yes, #method
is for the link on the local method, and is available on the mouse over anchor. #tymethod
would be the link to the trait definition, on the function name, but it's not available here and this fix removes it.
I think I added the MCVE with the correct annotations. The test is working with this PR, and not without |
src/librustdoc/html/render/mod.rs
Outdated
.unwrap_or_else(|| format!("#{}.{}", ty, name)) | ||
match href(did.expect_real(), cx) { | ||
Ok(p) => Some(format!("{}#{}.{}", p.0, ty, name)), | ||
Err(HrefError::DocumentationNotBuilt) => None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I think I see why I was confused - rustdoc can never be missing the documentation for the current crate, because it's building it right now.
Can you add an assert that ty == ItemType::TyMethod
with a comment that TyMethods only appear for extern crates?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assert makes this test fail (with this include).
It seems it's possible to have a ItemType::Method
when reexporting a struct with a method for which doc has not been built. I changed this PR to still allow this link as it's valid
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you happen to know why the test didn't fail without the assert? It seems to be testing that the method.
link is generated - maybe it also needs to test that a tymethod.
link is generated too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we are importing and using the struct in the current crate, we are importing its impl with its method, but the source is in the dependency and the doc is not built there...
The existing assertion was not on the link itself, but on the presence of the function in the doc. I added assertions on the links generated
This comment has been minimized.
This comment has been minimized.
c466de2
to
a75e629
Compare
I don't really understand why this works, but I also won't have time to look into it in the near future and the tests seem about right, so r=me with both comments addressed(#86662 (comment) and #86662 (comment)). |
Thank you for your reviews, I think I addressed the two comments r? @jyn514 |
Looks good to me, but I want to wait for CI to pass. @bors delegate=mockersf (please use r=jyn514) |
✌️ @mockersf can now approve this pull request |
@bors r=jyn514 |
📌 Commit 450c28a has been approved by |
☀️ Test successful - checks-actions |
fix #86620
href
method to raise the actual error it had instead of anOption
I did not manage to make a small reproducer, I think it happens in a situation where
r? @jyn514