Skip to content

update_lints rewrite: Add structure and --print-only #2985

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

Merged
merged 10 commits into from
Sep 6, 2018

Conversation

phansch
Copy link
Member

@phansch phansch commented Jul 31, 2018

Part of #2882

This adds a clippy_dev project that currently uses clap, regex and lazy_static to print a list of lints. For now it only replaces the lint printing in update_lints.py.

Running util/dev update_lints --print-only from scratch takes 45s on my machine.

I could not make it use a stable toolchain because somehow running cargo test in the subdirectory parses the Clippy Cargo.toml, too:

$ cd clippy_dev && cargo run -- update_lints --print-only
error: failed to parse manifest at `/home/phansch/code/rust-clippy/Cargo.toml`

Caused by:
  the cargo feature `edition` requires a nightly version of Cargo, but this is the `stable` channel

use std::io::prelude::*;

lazy_static! {
static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(r#"declare_clippy_lint!\s*[\{(]\s*pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*(?P<cat>[a-z_]+)\s*,\s*"(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]"#).unwrap();
Copy link
Member Author

Choose a reason for hiding this comment

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

Is there a way to split these up over multiple lines like in the python script? That would make them much more readable.
https://github.com/rust-lang-nursery/rust-clippy/blob/97840090b78ce1f370c3380e8a703da420fe3a98/util/update_lints.py#L11-L15

Copy link
Member

Choose a reason for hiding this comment

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

yes

"nursery",
"restriction"
];
// We could use itertools' group_by to make this much more concise:
Copy link
Member Author

Choose a reason for hiding this comment

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

Just saw that we already use itertools in Clippy, so I will use that in here, too.


pub fn collect_all() -> Vec<Lint> {
let mut lints = vec![];
for direntry in lint_files() {
Copy link

Choose a reason for hiding this comment

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

dir_entry (instead of direntry) is easier on my eyes

@phansch
Copy link
Member Author

phansch commented Aug 16, 2018

(will get back to this and the other PR and the end of the month)

@phansch phansch added the S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) label Aug 29, 2018
@phansch phansch force-pushed the riir_update_lints branch 3 times, most recently from 77fa255 to cf89c58 Compare September 2, 2018 08:00
@phansch phansch removed the S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) label Sep 2, 2018
@phansch phansch changed the title WIP: update_lints rewrite: Add structure and --print-only update_lints rewrite: Add structure and --print-only Sep 5, 2018
@phansch phansch added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Sep 5, 2018
@phansch
Copy link
Member Author

phansch commented Sep 5, 2018

I think this is ready for a final review

@oli-obk
Copy link
Contributor

oli-obk commented Sep 5, 2018

I could not make it use a stable toolchain because somehow running cargo test in the subdirectory parses the Clippy Cargo.toml, too:

I think this is because it thinks it's part of the workspace. Not sure if that is resolveable

@@ -0,0 +1,38 @@
# Used by Travis to be able to push:
/.github/deploy_key
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to just update our main .gitignore?

}
}

pub fn active_lints(lints: &[Lint]) -> Vec<Lint> {
Copy link
Contributor

Choose a reason for hiding this comment

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

I kind of feel like all the Vec returning functions here should be returning impl Iterator<Item=Lint>. That does require some string allocations, but should generally be possible.

Not a blocker for this PR, just a nice to have. You can also open an issue and leave it as a "good first issue"

@phansch phansch added S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Sep 5, 2018
This makes the API of `lib.rs` a bit more flexible.
@@ -56,22 +57,22 @@ impl Lint {
}
}

pub fn collect_all() -> Vec<Lint> {
pub fn gather_all() -> impl Iterator<Item=Lint> {
Copy link
Contributor

Choose a reason for hiding this comment

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

this entire function can probably be lint_files().flat_map(identity)

Copy link
Member Author

@phansch phansch Sep 6, 2018

Choose a reason for hiding this comment

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

This is my favorite refactoring in Ruby and I'm SO happy it's possible in Rust 🎉

let mut file = fs::File::open(dir_entry.path()).unwrap();
let mut content = String::new();
file.read_to_string(&mut content).unwrap();
parse_contents(&content, dir_entry.path().file_stem().unwrap().to_str().unwrap())
}

fn parse_contents(content: &str, filename: &str) -> Vec<Lint> {
fn parse_contents(content: &str, filename: &str) -> impl Iterator<Item=Lint> {
let mut lints: Vec<Lint> = DEC_CLIPPY_LINT_RE
Copy link
Contributor

Choose a reason for hiding this comment

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

chain the two iterators and remove the collect&append&into_iter

Copy link
Member Author

Choose a reason for hiding this comment

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

If I don't collect the map result, I run into a lot of lifetime issues, because contents and filename are used in the iterator and would outlive the function. I will push the changes in a bit with a comment.

}

/// Collects all .rs files in the `clippy_lints/src` directory
fn lint_files() -> Vec<fs::DirEntry> {
fn lint_files() -> impl Iterator<Item=fs::DirEntry> {
let paths = fs::read_dir("../clippy_lints/src").unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

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

remove the intermedate paths variable

.captures_iter(content)
.map(|m| Lint::new( &m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), filename));
// Removing the `.collect::<Vec<Lint>>().into_iter()` causes some lifetime issues due to the map
lints.chain(deprecated).collect::<Vec<Lint>>().into_iter()
Copy link
Member Author

Choose a reason for hiding this comment

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

If I remove the collect().into_iter() here, I get lifetime 'static' required for content and filename, which makes sense because they are used in the iterator and consumed outside of this function. I feel like making them static doesn't make sense here and would make the code more complicated to read.

@oli-obk oli-obk merged commit dc164f4 into rust-lang:master Sep 6, 2018
@phansch phansch deleted the riir_update_lints branch September 6, 2018 08:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants