Skip to content
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

Merged
merged 7 commits into from
Jul 16, 2021

Conversation

mockersf
Copy link
Contributor

fix #86620

  • changes href method to raise the actual error it had instead of an Option
  • set the href link correctly in case of an error

I did not manage to make a small reproducer, I think it happens in a situation where

  • crate A expose a trait with a blanket impl
  • crate B use the trait from crate A
  • crate C use types from crate B
  • building docs for crate C without dependencies

r? @jyn514

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 27, 2021
Copy link
Member

@jyn514 jyn514 left a 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.

src/librustdoc/html/render/mod.rs Show resolved Hide resolved
@@ -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 {
Copy link
Member

@jyn514 jyn514 Jun 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would help quite a lot with #82014 I think :) good idea.

(So I remember: the perma-link for this is 8f19606)

@jyn514
Copy link
Member

jyn514 commented Jul 2, 2021

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.

Copy link
Member

@jyn514 jyn514 left a 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.

src/librustdoc/html/format.rs Outdated Show resolved Hide resolved
src/librustdoc/html/format.rs Outdated Show resolved Hide resolved
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 {
Copy link
Member

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?

Suggested change
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.)

Copy link
Contributor Author

@mockersf mockersf Jul 4, 2021

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

Copy link
Member

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

Copy link
Member

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);

Copy link
Member

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/format.rs Show resolved Hide resolved
Comment on lines 887 to 874
match href(did.expect_real(), cx) {
Ok(p) => Some(format!("{}#{}.{}", p.0, ty, name)),
Err(HrefError::UnknownLocation) => None,
Err(_) => Some(format!("#{}.{}", ty, name)),
}
Copy link
Member

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.

Copy link
Contributor Author

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.

@jyn514 jyn514 added A-cross-crate-reexports Area: Documentation that has been re-exported from a different crate S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 2, 2021
@mockersf
Copy link
Contributor Author

mockersf commented Jul 4, 2021

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.

I think I added the MCVE with the correct annotations. The test is working with this PR, and not without

.unwrap_or_else(|| format!("#{}.{}", ty, name))
match href(did.expect_real(), cx) {
Ok(p) => Some(format!("{}#{}.{}", p.0, ty, name)),
Err(HrefError::DocumentationNotBuilt) => None,
Copy link
Member

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?

Copy link
Contributor Author

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

Copy link
Member

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?

Copy link
Contributor Author

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

@bors

This comment has been minimized.

@mockersf mockersf force-pushed the fix-86620-link-unknown-location branch from c466de2 to a75e629 Compare July 6, 2021 20:47
@jyn514
Copy link
Member

jyn514 commented Jul 10, 2021

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)).

@mockersf
Copy link
Contributor Author

Thank you for your reviews, I think I addressed the two comments

r? @jyn514

@jyn514
Copy link
Member

jyn514 commented Jul 14, 2021

Looks good to me, but I want to wait for CI to pass.

@bors delegate=mockersf (please use r=jyn514)

@bors
Copy link
Contributor

bors commented Jul 14, 2021

✌️ @mockersf can now approve this pull request

@mockersf
Copy link
Contributor Author

@bors r=jyn514

@bors
Copy link
Contributor

bors commented Jul 16, 2021

📌 Commit 450c28a has been approved by jyn514

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 16, 2021
@bors
Copy link
Contributor

bors commented Jul 16, 2021

⌛ Testing commit 450c28a with merge a6470c7...

@bors
Copy link
Contributor

bors commented Jul 16, 2021

☀️ Test successful - checks-actions
Approved by: jyn514
Pushing a6470c7 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Jul 16, 2021
@bors bors merged commit a6470c7 into rust-lang:master Jul 16, 2021
@rustbot rustbot added this to the 1.55.0 milestone Jul 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-cross-crate-reexports Area: Documentation that has been re-exported from a different crate merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

rustdoc links to the wrong method anchor
5 participants