-
Notifications
You must be signed in to change notification settings - Fork 899
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
Add ImportGranularity::ModuleCondensed
#5781
base: master
Are you sure you want to change the base?
Conversation
@flip1995 Sorry to ping you, but would you be able to comment on whether this is Clippy's preferred convention? |
We don't really have a import convention in Clippy, other than that we don't allow wildcard imports, enforced by one of our That being said, I like this convention and would adapt it for Clippy. Especially when 2/3 of Clippy follow it already. |
In principle yes. I don't envision us adding any variants ourselves but we're open to supporting others so long as someone submits the PR like this and it doesn't add any undue maintenance burden for us. We're unlikely to be able to spend any review cycles on this for the foreseeable future though. Haven't looked at the specifics of the proposed change yet, but would suggest including a |
@calebcartwright Thank you very much for your reply. I am currently travelling, but will add the |
1646197
to
6a1142d
Compare
Done. Please let me know what else is needed. Thanks. |
@fee1-dead @CosmicHorrorDev - I know you're both busy (with both Rust and life things 😄), but just tagging this as one for you to potentially review in case you're interested and get around to it before Yacin and/or myself. I'm in favor of supporting the style associated with the variant, but haven't had a chance to look at the associated implementation |
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.
In addition, could you add unit test cases to test this behavior? thanks.
src/imports.rs
Outdated
let mut n = 0; | ||
while n < self.path.len() && n < other.path.len() && self.path[n] == other.path[n] { | ||
n += 1; | ||
} | ||
n |
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.
Using an iterator e.g. something like below should work better?
let mut n = 0; | |
while n < self.path.len() && n < other.path.len() && self.path[n] == other.path[n] { | |
n += 1; | |
} | |
n | |
self.path.iter().zip(other.iter()).take_while(|(a, b)| a == b).count() |
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.
Nice!
// Search front-to-back for a tree to merge the singleton into. If | ||
// multiple trees are equally good candidates, prefer the earliest one. |
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.
Could you add this as a unit test/comment the part in the ui test that is exercising the "prefer the earliest one" logic?
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 added a unit test (with an explanation).
src/imports.rs
Outdated
for n in (0..use_trees.len()).rev() { | ||
let singleton = &use_trees[n]; |
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 prefer if you use iterators over using indices, perhaps using iter_mut
and into_slice
. If that seems too complicated, then it's okay for this to remain using indices.
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'm not opposed to the idea, but I'm having a hard time seeing how it could work (probably my failure of imagination).
My difficulties include:
- The inner loop must only consider the trees at indices
0..n
. So we would need to somehow recover the bound from the outer loop. (We could useenumerate
, but I'm not sure that would be more clear.) - If the inner loop selects a candidate for absorption, the tree at index
n
getsswap_remove
d, andswap_remove
requires that the index be passed. - I'm assuming you mean that the inner loop should also use an iterator. In that case, the inner loop iterator would need to be mutable. But then wouldn't we run into borrow checker problems, with immutable and mutable iterators trying to refer to the same vector?
src/imports.rs
Outdated
continue; | ||
} | ||
if curr_len < 1 | ||
|| !(curr_tree.is_singleton() || curr_len + 1 == curr_tree.path.len()) |
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 logic is a bit hard to read. Does the below preserve the same behavior?
|| !(curr_tree.is_singleton() || curr_len + 1 == curr_tree.path.len()) | |
|| !curr_tree.is_singleton() && curr_len + 1 != curr_tree.path.len() |
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.
Yes, I think so.
Done. (Apologies, as I hadn't noticed the existing unit tests.) |
41fc046
to
bfa696f
Compare
Sorry for the force push (minor grammatical adjustment). It should be good 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.
LGTM
Point very well taken, but I thought I would check in. Any chance of merging this? |
I thought I would check in again. Any chance of merging this? |
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.
@smoelius I don't think we're ready to move forward with this one just yet. I haven't spent too much time reviewing the details of condense_use_trees
, but by looking at the test cases, the way the relative order of imports changes strikes me as odd. Do you think there's a way to better preserve the order?
Also, reorder_imports=true
is on by default. can we add test cases where we set reorder_imports=false
. I'd want to see what the output looks like in that case.
src/imports.rs
Outdated
} | ||
|
||
fn is_singleton(&self) -> bool { | ||
!matches!(self.path.last().unwrap().kind, UseSegmentKind::List(_)) |
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 we find a way to write this without unwrap()
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.
Sure. (FWIW, that pattern appears elsewhere in the file, though.)
use a::g::{h, i}; | ||
use a::j::k::{self, l}; | ||
use a::j::{self, m}; | ||
use a::n::{o::p, q}; | ||
use a::{b::c, d::e, f}; | ||
pub use a::{r::s, t}; | ||
use b::{self, c::d}; |
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 what we started with:
use a::{b::c, d::e};
use a::{f, g::{h, i}};
use a::{j::{self, k::{self, l}, m}, n::{o::p, q}};
pub use a::{r::s, t};
use b::{c::d, self};
I'm finding it a odd that the relative order of the import got moved around like they did. For example use a::{b::c, d::e};
was the first import, but then it got moved down to the 5th import after merging. I think I would have expected the output to look more like this:
use a::{b::c, d::e, f};
use a::g::{h, i};
use a::j::{self, m};
use a::j::k::{self, l};
use a::n::{o::p, q};
pub use a::{r::s, t};
use b::{self, c::d};
I forget if visibility impacts import sorting. If it doesn't, I also would have expected pub use a::{r::s, t};
to be the second import. Something like this:
use a::{b::c, d::e, f};
pub use a::{r::s, t};
use a::g::{h, i};
use a::j::{self, m};
use a::j::k::{self, l};
use a::n::{o::p, q};
use b::{self, c::d};
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.
For both of the examples given after "I think I would have expected...", vanilla rustfmt
reorders them as in the referenced code (playground).
I think this case may be the culprit:
Line 955 in 6356fca
(Ident(..), _) => Ordering::Less, |
That is, a single identifier (like g
) is considered "less" than a list (like {b::c, d::e, f}
).
If you agree with my analysis, then maybe the sort order is outside the scope of this PR?
EDIT: Ignoring reorder_imports
still needs to be addressed, of course.
I added such a test case. I also took the liberty of adding such a test case for Apologies, as I did not realize there was a |
@ytmimi I think Also, it appears that |
@ytmimi Would it be possible to give this PR another look? |
Given that
imports_granularity
is unstable, is this something you would consider merging?From the docs I added:
I have long perceived this to be Clippy's convention. I ran this on Clippy's source code and about 2/3 of the files were left unchanged. Since this supposed convention has been enforced by hand, I consider this confirmation.