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

feature: add new lint pub_underscore_fields #10283

Merged
merged 1 commit into from
Dec 29, 2023

Conversation

ParkMyCar
Copy link
Contributor

@ParkMyCar ParkMyCar commented Feb 3, 2023

fixes: #10282

This PR introduces a new lint pub_underscore_fields that lints when a user has marked a field of a struct as public, but also prefixed it with an underscore (_). This is something users should avoid because the two ideas are contradictory. Prefixing a field with an _ is inferred as the field being unused, but making a field public infers that it will be used.

  • Followed [lint naming conventions][lint_naming]
    • I believe I followed the naming conventions, more than happy to update the naming if I did not :)
  • Added passing UI tests (including committed .stderr file)
  • cargo test passes locally
  • Executed cargo dev update_lints
  • Added lint documentation
  • Run cargo dev fmt

changelog: new lint: [pub_underscore_fields]
#10283

@rustbot
Copy link
Collaborator

rustbot commented Feb 3, 2023

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @flip1995 (or someone else) soon.

Please see the contribution instructions for more information.

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Feb 3, 2023
@bors
Copy link
Collaborator

bors commented Feb 23, 2023

☔ The latest upstream changes (presumably #10392) made this pull request unmergeable. Please resolve the merge conflicts.

@ParkMyCar
Copy link
Contributor Author

Hey @flip1995, if you wouldn't mind taking a look at this when you get the chance, it would be much appreciated! No rush though :)

@bors
Copy link
Collaborator

bors commented Mar 16, 2023

☔ The latest upstream changes (presumably #10481) made this pull request unmergeable. Please resolve the merge conflicts.

@blyxyas
Copy link
Member

blyxyas commented Oct 7, 2023

@ParkMyCar Philipp stopped being on the reviewer rotation a few months ago, are you still interested in continuing with this development? ฅ^•ﻌ•^ฅ

r? @blyxyas

@rustbot rustbot assigned blyxyas and unassigned flip1995 Oct 7, 2023
@ParkMyCar
Copy link
Contributor Author

@ParkMyCar Philipp stopped being on the reviewer rotation a few months ago, are you still interested in continuing with this development? ฅ^•ﻌ•^ฅ

r? @blyxyas

For sure! I just rebased off of master and updated the lint version, whenever you have time let me know if there is any other feedback :)

Copy link
Member

@blyxyas blyxyas left a comment

Choose a reason for hiding this comment

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

Very good for a first review! Just a couple minor changes and I think this is it ❤️ |ΦωΦ|

return;
};

let msg = "field marked as public but also inferred as unused because it's prefixed with `_`";
Copy link
Member

Choose a reason for hiding this comment

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

I'd just inline the message, but if you want to have it as a separate variable, put it later in the checks (just before span_lint_and_help). We don't want to allocate innecesarily.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Inlined it is :)

};

let msg = "field marked as public but also inferred as unused because it's prefixed with `_`";
for field in st.fields().iter() {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
for field in st.fields().iter() {
for field in st.fields() {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

clippy_lints/src/pub_underscore_fields.rs Show resolved Hide resolved
@Alexendoo
Copy link
Member

It would be good if this ignored PhantomData fields (it's common to underscore prefix them) and fields that are #[doc(hidden)]

@ParkMyCar
Copy link
Contributor Author

It would be good if this ignored PhantomData fields (it's common to underscore prefix them) and fields that are #[doc(hidden)]

Thanks for the feedback @Alexendoo! I'm not sure I agree though. AFAIU prefixing a field name with an underscore generally indicates that field should be ignored, if some part of your code needs to use the PhantomData marker, then it should not be prefixed, same with #[doc_hidden]. I'd be more than happy to make this change, but it's not totally clear to me why these would need to be special cased, could you explain more or provide an example? Thanks :)

@blyxyas
Copy link
Member

blyxyas commented Oct 11, 2023

PhantomData<T> is a data type used for enforcing type rules. It isn't meant to be used because it holds literally 0 data, so using _phantom is really common [~84K occurrences].


On the topic of #[doc(hidden)], I'm not sure of any strong reasons of ignoring them, some more information would be appreciated.

@@ -20,9 +20,15 @@ declare_clippy_lint! {
/// ```
/// Use instead:
/// ```rust
/// struct FileHandle {
/// struct FileHandle_Foo {
Copy link
Member

Choose a reason for hiding this comment

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

Mixing PascalCase with underscores hehe 🐈
For future reference, you can use attributes like should_panic on your code blocks so that these name collisions don't matter.

Copy link
Member

Choose a reason for hiding this comment

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

You can make it two separate code blocks

```rust
struct FileHandle { .. }
```
or
```rust
struct FileHandle { .. }
```

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🤦‍♂️ yep totally missed this, updated it to be two code blocks!

@Alexendoo
Copy link
Member

doc(hidden) + underscore prefix is used to drive home the "please don't use this" message, that the field is only public for some implementation reason such as being used in a macro expansion

e.g. https://docs.rs/enumset/1.1.2/src/enumset/set.rs.html#125-130

@ParkMyCar
Copy link
Contributor Author

@blyxyas @Alexendoo thanks for the examples! I'm thoroughly convinced, I updated the lint to be a LatePass so we can get type info. Then skip fields that are #[doc(hidden)] or use PhantomData`.

I struggled a bit to get the visibility settings right, if there's an easier to detect the range of "pub" visibilities we want to guard against, please let me know!

@ParkMyCar
Copy link
Contributor Author

Whoops, just realized I forgot to add tests for the new #[doc(hidden)] and PhantomData checks, let me do that!

Copy link
Member

@blyxyas blyxyas left a comment

Choose a reason for hiding this comment

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

Just some polishing and I think this is ready! Thanks for the patience! ❤️ (=^・ω・^=)

clippy_lints/src/pub_underscore_fields.rs Outdated Show resolved Hide resolved
clippy_lints/src/pub_underscore_fields.rs Outdated Show resolved Hide resolved
clippy_lints/src/pub_underscore_fields.rs Outdated Show resolved Hide resolved
clippy_lints/src/pub_underscore_fields.rs Outdated Show resolved Hide resolved
clippy_lints/src/pub_underscore_fields.rs Outdated Show resolved Hide resolved
Comment on lines 53 to 62
let is_visible = |field: &FieldDef<'_>| {
let parent = cx.tcx.parent_module_from_def_id(field.def_id);
let grandparent = cx.tcx.parent_module_from_def_id(parent.into());
let visibility = cx.tcx.visibility(field.def_id);

let case_1 = parent == grandparent && !field.vis_span.is_empty();
let case_2 = visibility != Visibility::Restricted(parent.to_def_id());

case_1 || case_2
};
Copy link
Member

Choose a reason for hiding this comment

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

Can try cx.effective_visibilities.is_exported(field.def_id)) for this

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 that, unfortunately it didn't work :/

Copy link
Member

Choose a reason for hiding this comment

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

I think the issue is the test file, none of the fields in it are actually publicly reachable. You'd have to move the definitions outside of fn main() {} and make the inner/inner2 modules public

Copy link
Member

Choose a reason for hiding this comment

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

is_exported doesn't lint for pub(...), and it seems like it has some problems with fields of type Option<T> for some reason?

I don't see it as a requirement.

Copy link
Member

@Alexendoo Alexendoo Oct 16, 2023

Choose a reason for hiding this comment

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

The effective visibility is what matters for the lint though

Fields prefixed with an _ are inferred as unused, which suggests it should not be marked as pub, because marking it as pub infers it will be used.

pub(crate), or pub where the field is not publicly reachable does not mark the field as used

What's the issue with Option fields?

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, now I'm not sure.
We could lint for any field that is public and its name starts with _, which is what the name of lint implies. Or we could analyze the description a little bit more and just lint when the pub is actually useful.

@ParkMyCar
Copy link
Contributor Author

Just some polishing and I think this is ready! Thanks for the patience! ❤️ (=^・ω・^=)

Sweet! Made all of your suggested changes!

Copy link
Member

@blyxyas blyxyas left a comment

Choose a reason for hiding this comment

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

Just the version upgrade and that's all, thanks ❤️!

clippy_lints/src/pub_underscore_fields.rs Outdated Show resolved Hide resolved
@blyxyas
Copy link
Member

blyxyas commented Oct 16, 2023

Could you please rebase and squash these commits into 1 or 2 relevant ones?

Copy link
Member

@blyxyas blyxyas left a comment

Choose a reason for hiding this comment

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

And also, could you run cargo collect-metadata

@ParkMyCar
Copy link
Contributor Author

And also, could you run cargo collect-metadata

Updated to 1.77, ran cargo collect-metadata, and squashed all of the commits into one!

---
**Affected lints:**
* [`pub_underscore_fields`](https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields)
* [`or`](https://rust-lang.github.io/rust-clippy/master/index.html#or)
Copy link
Member

Choose a reason for hiding this comment

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

I'm not really sure why this is here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Me either! It's what cargo collect-metadata generated, other lints seem to have similar "Affected lints" sections :)

Copy link
Member

Choose a reason for hiding this comment

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

I meant the or lint, that doesn't exist xD

@blyxyas
Copy link
Member

blyxyas commented Dec 29, 2023

@bors try

@bors
Copy link
Collaborator

bors commented Dec 29, 2023

⌛ Trying commit 73a3636 with merge 493b5a3...

bors added a commit that referenced this pull request Dec 29, 2023
feature: add new lint `pub_underscore_fields`

fixes: #10282

This PR introduces a new lint `pub_underscore_fields` that lints when a user has marked a field of a struct as public, but also prefixed it with an underscore (`_`). This is something users should avoid because the two ideas are contradictory. Prefixing a field with an `_` is inferred as the field being unused, but making a field public infers that it will be used.

- \[x] Followed [lint naming conventions][lint_naming]
  - I believe I followed the naming conventions, more than happy to update the naming if I did not :)
- \[x] Added passing UI tests (including committed `.stderr` file)
- \[x] `cargo test` passes locally
- \[x] Executed `cargo dev update_lints`
- \[x] Added lint documentation
- \[x] Run `cargo dev fmt`

---

changelog: new lint: [`pub_underscore_fields`]
[#10283](#10283)
<!-- changelog_checked -->
@bors
Copy link
Collaborator

bors commented Dec 29, 2023

☀️ Try build successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Build commit: 493b5a3 (493b5a31558ca205f5fe5c3a13bca6652baf16bc)

- add a new late pass lint, with config options
- add ui tests for both variations of config option
- update CHANGELOG.md

github feedback

bump version to 1.77 and run cargo collect-metadata

Change `,` to `;` in `conf.rs`
@blyxyas
Copy link
Member

blyxyas commented Dec 29, 2023

I changed that , to a ;, this is a bug in our metadata collector, it seems that it just gets any word after a comma. I already pushed this to your fork.

Let's hope that everything goes well this time (=^・^=)

@blyxyas
Copy link
Member

blyxyas commented Dec 29, 2023

@bors r+

@bors
Copy link
Collaborator

bors commented Dec 29, 2023

📌 Commit fa7dd1c has been approved by blyxyas

It is now in the queue for this repository.

@bors
Copy link
Collaborator

bors commented Dec 29, 2023

⌛ Testing commit fa7dd1c with merge 174a0d7...

@bors
Copy link
Collaborator

bors commented Dec 29, 2023

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: blyxyas
Pushing 174a0d7 to master...

@ParkMyCar
Copy link
Contributor Author

Woo! Thank you @blyxyas for reviewing this PR and getting it merged, I appreciate it! 😊

@GrantGryczan
Copy link

GrantGryczan commented Jan 13, 2024

It's spelled "publicly", not "publically". I recommend fixing that in the PublicallyExported value. (If needed, I can submit a separate issue for this.)

Furthermore, the pub-underscore-fields-behavior option has no description in the documentation, so I've got no clue what it does. I don't even know what values it can be set to other than its default.

@blyxyas
Copy link
Member

blyxyas commented Jan 13, 2024

I'll fix this myself. Thanks for the report.

bors added a commit that referenced this pull request Jan 20, 2024
Add . to end of lint lists in configuration + Fix typo in pub_underscore_fields_behavior

Fixes #10283 (comment)

In the "/// Lint: " list on each configuration option, you have to end with a dot. If the lint list doesn't have a dot, the configuration won't have documentation.

This PR adds those missing dots in some of the configuration, thus also adding their documentation.

changelog: Fix bug where a lot of config documentation wasn't showing.
changelog: Fix typo in `pub_underscore_fields_behavior` (`PublicallyExported` -> `PubliclyExported`)
bors added a commit that referenced this pull request Jan 20, 2024
Add . to end of lint lists in configuration + Fix typo in pub_underscore_fields_behavior

Fixes #10283 (comment)

In the "/// Lint: " list on each configuration option, you have to end with a dot. If the lint list doesn't have a dot, the configuration won't have documentation.

This PR adds those missing dots in some of the configuration, thus also adding their documentation.

changelog: Fix bug where a lot of config documentation wasn't showing.
changelog: Fix typo in `pub_underscore_fields_behavior` (`PublicallyExported` -> `PubliclyExported`)
bors added a commit that referenced this pull request Jan 20, 2024
Add . to end of lint lists in configuration + Fix typo in pub_underscore_fields_behavior

Fixes #10283 (comment)

In the "/// Lint: " list on each configuration option, you have to end with a dot. If the lint list doesn't have a dot, the configuration won't have documentation.

This PR adds those missing dots in some of the configuration, thus also adding their documentation.

changelog: Fix bug where a lot of config documentation wasn't showing.
changelog: Fix typo in `pub_underscore_fields_behavior` (`PublicallyExported` -> `PubliclyExported`)
bors added a commit that referenced this pull request Jan 20, 2024
Add . to end of lint lists in configuration + Fix typo in pub_underscore_fields_behavior

Fixes #10283 (comment)

In the "/// Lint: " list on each configuration option, you have to end with a dot. If the lint list doesn't have a dot, the configuration won't have documentation.

This PR adds those missing dots in some of the configuration, thus also adding their documentation.

changelog: Fix bug where a lot of config documentation wasn't showing.
changelog: Fix typo in `pub_underscore_fields_behavior` (`PublicallyExported` -> `PubliclyExported`)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feature: Warn for pub fields prefixed with an underscore
7 participants