10440: Fix Clippy warnings and replace some `if let`s with `match` r=Veykril a=arzg
I decided to try fixing a bunch of Clippy warnings. I am aware of this project’s opinion of Clippy (I have read both [rust-lang/clippy#5537](https://github.com/rust-lang/rust-clippy/issues/5537) and [rust-analyzer/rowan#57 (comment)](https://github.com/rust-analyzer/rowan/pull/57#discussion_r415676159)), so I totally understand if part of or the entirety of this PR is rejected. In particular, I can see how the semicolons and `if let` vs `match` commits provide comparatively little benefit when compared to the ensuing churn.
I tried to separate each kind of change into its own commit to make it easier to discard certain changes. I also only applied Clippy suggestions where I thought they provided a definite improvement to the code (apart from semicolons, which is IMO more of a formatting/consistency question than a linting question). In the end I accumulated a list of 28 Clippy lints I ignored entirely.
Sidenote: I should really have asked about this on Zulip before going through all 1,555 `if let`s in the codebase to decide which ones definitely look better as `match` :P
Co-authored-by: Aramis Razzaghipour <aramisnoah@gmail.com>
Consider these expples
{ 92 }
async { 92 }
'a: { 92 }
#[a] { 92 }
Previously the tree for them were
BLOCK_EXPR
{ ... }
EFFECT_EXPR
async
BLOCK_EXPR
{ ... }
EFFECT_EXPR
'a:
BLOCK_EXPR
{ ... }
BLOCK_EXPR
#[a]
{ ... }
As you see, it gets progressively worse :) The last two items are
especially odd. The last one even violates the balanced curleys
invariant we have (#10357) The new approach is to say that the stuff in
`{}` is stmt_list, and the block is stmt_list + optional modifiers
BLOCK_EXPR
STMT_LIST
{ ... }
BLOCK_EXPR
async
STMT_LIST
{ ... }
BLOCK_EXPR
'a:
STMT_LIST
{ ... }
BLOCK_EXPR
#[a]
STMT_LIST
{ ... }
9944: internal: introduce in-place indenting API r=matklad a=iDawer
Introduce `edit_in_place::Indent` that uses mutable tree API and intended to replace `edit::AstNodeEdit`.
Closes#9903
Co-authored-by: Dawer <7803845+iDawer@users.noreply.github.com>
10001: Sort enum variant r=Veykril a=vsrs
A small fix to the problem noted by `@lnicola` :
> ![sort-fields](https://user-images.githubusercontent.com/308347/129513196-4ffc7937-be58-44d4-9ec7-ba8745dcb460.gif)
>
> (note the slight inconsistency here: to sort the variants of `Animal` I have to select the enum name, but to sort the fields of `Cat` I have to select the fields themselves)
Co-authored-by: vsrs <vit@conrlab.com>
9972: refactor : function generation assists r=Veykril a=mahdi-frms
Separated code generation from finding position for generated code. This will be ground work for introducing static associated function generation.
Co-authored-by: mahdi-frms <mahdif1380@outlook.com>
9962: Add empty-body check to replace_match_with_if_let and re-prioritize choices r=elkowar a=elkowar
This PR changes some behaviour of the `replace_match_with_if_let` ide-assist.
Concretely, it makes two changes:
it introduces a check for empty expression bodies. This means that checks of the shape
```rs
match x {
A => {}
B => {
println!("hi");
}
}
```
will prefer to use the B branch as the first (and only) variant.
It also reprioritizes the importance of "happy" and "sad" patterns.
Concretely, if there are reasons to prefer having the sad pattern be the first (/only) pattern,
it will follow these.
This means that in the case of
```rs
match x {
Ok(_) => {
println!("Success");
}
Err(e) => {
println!("Failure: {}", e);
}
}
```
the `Err` variant will correctly be used as the first expression in the generated if.
Up until now, the generated code was actually invalid, as it would generate
```rs
if let Ok(_) = x {
println!("Success");
} else {
println!("Failure: {}", e);
}
```
where `e` in the else branch is not defined.
Co-authored-by: elkowar <5300871+elkowar@users.noreply.github.com>
9855: feature: Destructure Tuple Assist r=Veykril a=Booksbaum
Part of #8673. This PR only handles tuples, not TupleStruct and RecordStruct.
Code Assist to destructure a tuple into its items:
![Destructure_Tuple_Assist](https://user-images.githubusercontent.com/15612932/129020107-775d7c94-dca7-4d1f-a0a2-cd63cabf4132.gif)
* Should work in nearly all pattern positions, like let assignment, function parameters, match arms, for loops, and nested variables (`if let Some($0t) = Some((1,2))`)
-> everywhere `IdentPat` is allowed
* Exception: If there's a sub-pattern (``@`):`
```rust
if let t @ (1..=3, 1..=3) = ... {}
// ^
```
-> `t` must be a `Name`; `TuplePat` (`(_0, _1)`) isn't allowed
* inside subpattern is ok:
```rust
let t @ (a, _) = ((1,2), 3);
// ^
```
->
```rust
let t @ ((_0, _1), _) = ((1,2), 3);
```
* Assist triggers only at tuple declaration, not tuple usage.
(might be useful especially when it creates a sub-pattern (after ``@`)` and only changes the usage under cursor -- but not part of this PR).
### References
References can be destructured:
```rust
let t = &(1,2);
// ^
let v = t.0;
```
->
```rust
let (_0, _1) = &(1,2);
let v = _0;
```
BUT: `t.0` and `_0` have different types (`i32` vs. `&i32`) -> `v` has now a different type.
I think that's acceptable: I think the destructure assist is mostly used in simple, immediate scopes and not huge existing code.
Additional Notes:
* `ref` has same behaviour (-> `ref` is kept for items)
```rust
let ref t = (1,2);
// ^
```
->
```rust
let (ref _0, ref _1) = (1,2);
```
* Rust IntelliJ Plugin: doesn't trigger with `&` or `ref` at all
### mutable
```rust
let mut t = (1,2);
// ^
```
->
```rust
let (mut _0, mut _1) = (1,2);
```
and
```rust
let t = &mut (1,2);
// ^
```
->
```rust
let (_0, _1) = &mut (1,2);
```
Again: with reference (`&mut`), `t.0` and `_0` have different types (`i32` vs `&mut i32`).
And there's an additional issue with `&mut` and assignment:
```rust
let t = &mut (1,2);
// ^
t.0 = 9;
```
->
```rust
let (_0, _1) = &mut (1,2);
_0 = 9;
// ^
// mismatched types
// expected `&mut {integer}`, found integer
// consider dereferencing here to assign to the mutable borrowed piece of memory
```
But I think that's quite a niche use case, so I don't catch that (`*_0 = 9;`)
Additional Notes:
* Rust IntelliJ Plugin: removes the `mut` (`let mut t = ...` -> `let (_0, _1) = ...`), doesn't trigger with `&mut`
### Binding after ``@``
Destructure tuple in sub-pattern is implemented:
```rust
let t = (1,2);
// ^
let v = t.0;
let f = t.into();
```
->
```rust
let t @ (_0, _1) = (1,2);
let v = _0;
let f = t.into();
```
BUT: Bindings after ``@`` aren't currently in stable and require `#![feature(bindings_after_at)]` (though should be generally [available quite soon](https://github.com/rust-lang/rust/pull/85305#event-5072889913) (with `1.56.0`)).
But I don't know how to check for an enabled feature -> Destructure tuple in sub-pattern [isn't enabled](a4ee6c7954/crates/ide_assists/src/handlers/destructure_tuple_binding.rs (L32)) yet.
* When Destructure in sub-pattern is enabled there are two assists:
* `Destructure tuple in place`:
```rust
let t = (1,2);
// ^
```
->
```rust
let (_0, _1) = (1,2);
let v = _0;
let f = /*t*/.into();
```
* `Destructure tuple in sub-pattern`:
```rust
let t = (1,2);
// ^
let v = t.0;
let f = t.into();
```
->
```rust
let t @ (_0, _1) = (1,2);
let v = _0;
let f = t.into();
```
* When Destructure in sub-pattern is disabled, only the first one is available and just named `Destructure tuple`
<br/>
<br/>
### Caveats
* Unlike in #8673 or IntelliJ rust plugin, I'm not leaving the previous tuple name at function calls.
**Reasoning**: It's not too unlikely the tuple variable shadows another variable. Destructuring the tuple while leaving the function call untouched, results in still a valid function call -- but now with another variable:
```rust
let t = (8,9);
let t = (1,2);
// ^
t.into()
```
=> Destructure Tuple
```rust
let t = (8,9);
let (_0, _1) = (1,2);
t.into()
```
`t.into()` is still valid -- using the first tuple.
Instead I comment out the tuple usage, which results in invalid code -> must be handled by user:
```rust
/*t*/.into()
```
* (though that might be a biased decision: For testing I just declared a lot of `t`s and quite ofen in lines next to each other...)
* Issue: there are some cases that results in still valid code:
* macro that accept the tuple as well as no arguments:
```rust
macro_rules! m {
() => { "foo" };
($e:expr) => { $e; "foo" };
}
let t = (1,2);
m!(t);
m!(/*t*/);
```
-> both calls are valid ([test](a4ee6c7954/crates/ide_assists/src/handlers/destructure_tuple_binding.rs (L1474)))
* Probably with tuple as return value. Changing the return value most likely results in an error -- but in another place; not where the tuple usage was.
-> not sure that's the best way....
Additional the tuple name surrounded by comment is more difficult to edit than just the name.
* Code Assists don't support snippet placeholder, and rust analyzer just the first `$0` -> unfortunately no editing of generated tuple item variables. Cursor (`$0`) is placed on first generated item.
<br/>
<br/>
### Issues
* Tuple index usage in macro calls aren't converted:
```rust
let t = (1,2);
// ^
let v = t.0;
println!("{}", t.0);
```
->
```rust
let (_0, _1) = (1,2);
let v = _0;
println!("{}", /*t*/.0);
```
([tests](a4ee6c7954/crates/ide_assists/src/handlers/destructure_tuple_binding.rs (L1294)))
* Issue is:
[name.syntax()](a4ee6c7954/crates/ide_assists/src/handlers/destructure_tuple_binding.rs (L242-L244)) in each [usage](a4ee6c7954/crates/ide_assists/src/handlers/destructure_tuple_binding.rs (L108-L113)) of a tuple is syntax & text_range in its file.
EXCEPT when tuple usage is in a macro call (`m!(t.0)`), the macro is expanded and syntax (and range) is based on that expanded macro, not in actual file.
That leads to several things:
* I cannot differentiate between calling the macro with the tuple or with tuple item:
```rust
macro_rules! m {
($t:expr, $i:expr) => { $t.0 + $i };
}
let t = (1,2);
m!(t, t.0);
```
-> both `t` usages are resolved as tuple index usage
* Range of resolved tuple index usage is in expanded macro, not in actual file
-> don't know where to replace index usage
-> tuple items passed into a macro are ignored, and only the tuple name itself is handled (uncommented)
* I'm not checking if the generated names conflict with already existing variables.
```rust
let _0 = 42; // >-|
let t = (1,2); // |
let v = _0; // <-|
// ^ 42
```
=> deconstruct tuple
```rust
let _0 = 42;
let (_0, _1) = (1,2); // >-|
let v = _0; // <-|
// ^ now 1
```
* I tried to get the scope at tuple declaration and its usages. And then iterate all names with [`process_all_names`](145b51f9da/crates/hir/src/semantics.rs (L935)). But that doesn't find all local names for declarations (`let t = (1,2)`) (for usages it does)
* This isn't unique to this Code Assist, but happen in others too (like `extract into variable` or `extract into function`). But here a name conflict is more likely (when destructuring multiple tuples, for examples nested ones (`let t = ((1,2),3)` -> `let (_0, _1) = ...` -> `let ((_0, _1), _1) = ...` -> error))
* IntelliJ rust plugin does handle this (-> name is `_00`)
Co-authored-by: BooksBaum <15612932+Booksbaum@users.noreply.github.com>
Note:
2nd Assist description is moved down: generated doc tests extracts now
all tests (previously only the first one). But it uses the first
`Assist` name -- which is the wrong one for the 2nd test. And 2nd assist
is currently disabled -> would fail anyway.
Previously, we only inverted comparison operators (< and the like) if
the type implemented Ord. This doesn't make sense: if `<` works, then
`>=` will work as well!
Extra semantic checks greatly reduce robustness and predictability of
the assist, it's better to keep things simple.
9871: Jump to generated func r=mahdi-frms a=rylev
Worked on this with `@yoshuawuyts.`
We thought we ran into an issue with the `generate_function` assist where the code was not being generated in a certain situations. However, it wasn't actually a bug just a very confusing implementation where the cursor is not moved to the newly generated function. This happened when the return type was successfully inferred (and not unit). The function would be generated, but selection would not be changed.
This can be very confusing: If the function is generated somewhat far from where the assist is being invoked, the user never sees that the code was generated (nor are they given the chance to actually implement the function body).
This PR makes it so that the cursor is _always_ moved to somewhere in the newly generated function. In addition, if we can infer unit as the type, then we do not still generate `-> ()` as the return type. Instead, we simply omit the return type.
This means the selection will move to either one of two places:
* A generated `-> ()` return type when we cannot successfully infer the return type.
* The `todo!()` body when we can successfully infer the return type.
Co-authored-by: Ryan Levick <me@ryanlevick.com>
9863: feat: Generate default trait fn impl when generating `PartialEq` r=yoshuawuyts a=yoshuawuyts
Implements a default trait function body when generating the `PartialEq` trait for a type. Thanks!
r? `@veykril`
Co-authored-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
9846: feat: Generate default trait fn impl when generating `Clone` r=Veykril a=yoshuawuyts
Implements a default trait function body when generating the `Clone` trait for a type. Thanks!
r? `@\veykril`
Co-authored-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
9804: Generate method from call r=matklad a=mahdi-frms
Needs a bit of refactoring. Tests also should be added.
Co-authored-by: mahdi-frms <mahdif1380@outlook.com>
9825: Generate default impl when converting #[derive(Default)] to manual impl r=Veykril a=yoshuawuyts
Similar to https://github.com/rust-analyzer/rust-analyzer/pull/9814, but for `#[derive(Default)]`. Thanks!
## Follow-up steps
I've added the tests inside `handlers/replace_derive_with_manual_impl.rs` again, but I'm planning a follow-up PR to extract these to `utils/` so we can share them between assists - and maybe even add another assist just for the purpose of testing these impls (e.g. `generate_default_trait_body`).
The step after _that_ is likely to fill out the remaining traits, so we can make it so whenever RA auto-completes a trait which also can be derived, we provide a default function body.
Co-authored-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
9814: Generate default impl when converting `#[derive(Debug)]` to manual impl r=yoshuawuyts a=yoshuawuyts
This patch makes it so when you convert `#[derive(Debug)]` to a manual impl, a default body is provided that's equivalent to the original output of `#[derive(Debug)]`. This should make it drastically easier to write custom `Debug` impls, especially when all you want to do is quickly omit a single field which is `!Debug`.
This is implemented for enums, record structs, tuple structs, empty structs - and it sets us up to implement variations on this in the future for other traits (like `PartialEq` and `Hash`).
Thanks!
## Codegen diff
This is the difference in codegen for record structs with this patch:
```diff
struct Foo {
bar: String,
}
impl fmt::Debug for Foo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- todo!();
+ f.debug_struct("Foo").field("bar", &self.bar).finish()
}
}
```
Co-authored-by: Irina Shestak <shestak.irina@gmail.com>
Co-authored-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
Co-authored-by: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
9739: generate function assist favors deref cmpt types r=matklad a=mahdi-frms
Fixes#9713
Although that's still not relying on sematic info.
Co-authored-by: mahdi-frms <mahdif1380@outlook.com>
9731: feat: Add `replace_char_with_string` assist r=Veykril a=Veykril
Adds the counterpart for the `replace_string_with_char` assist and fixes the assist not escaping the `'` in the string `"'"` when transforming that to a char.
bors r+
Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
9593: fix: Adding remove_unused_param for method and fixing same for assoc func r=matklad a=feniljain
Solves #9571
Co-authored-by: vi_mi <fenil.jain2018@vitstudent.ac.in>
9453: Add first-class limits. r=matklad,lnicola a=rbartlensky
Partially fixes#9286.
This introduces a new `Limits` structure which is passed as an input
to `SourceDatabase`. This makes limits accessible almost everywhere in
the code, since most places have a database in scope.
One downside of this approach is that whenever you query limits, you
essentially do an `Arc::clone` which is less than ideal.
Let me know if I missed anything, or would like me to take a different approach!
Co-authored-by: Robert Bartlensky <bartlensky.robert@gmail.com>
9652: Don't concat path in replace_qualified assist when they start with a keyword r=Veykril a=Veykril
Also keep the path if we can't find a path to the item instead of becoming non applicable.
bors r+
Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
9614: Parse input expressions for dbg! invocations in remove_dbg r=Veykril a=Veykril
Instead of inspecting the input tokentree manually, parse the input as `,` delimited expressions instead and act on that. This simplifies the assist quite a bit.
Fixes#8455
Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
9567: remove unneded special case r=matklad a=matklad
bors r+
🤖
9568: feat: add 'for' postfix completion r=lnicola a=mahdi-frms
![Peek 2021-07-11 16-45](https://user-images.githubusercontent.com/62165556/125194692-a0aaf780-e267-11eb-952a-81de7955d9a1.gif)
adds #9561
used ```ele``` as identifier for each element in the iteration
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
Co-authored-by: mahdi-frms <mahdif1380@outlook.com>
9553: minor: Disambiguate replace with if let assist labels r=Veykril a=Veykril
Turns out we have two assists for replacing something with `if let` constructs, so having the cursor on a `let` keyword inside a match gave you two identical assist labels which is rather confusing.
bors r+
Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
9555: feat: Enable `auto_import` on ident patterns r=Veykril a=Veykril
Helpful for when you want to import a type in a pattern right before destructuring it.
9556: Bump deps r=lnicola a=lnicola
bors r+
Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
Co-authored-by: Laurențiu Nicola <lnicola@dend.ro>
9500: internal: Only inline closure, literal and local arguments when used once r=Veykril a=Veykril
See https://github.com/rust-analyzer/rust-analyzer/pull/9474#discussion_r663881507 for reasoning.
This still inlines single use closures and literals as naming these is usually not as useful. Prime examples being the Option/Result consuming functions like `map_or` etc.
Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
* Keep codegen adjacent to the relevant crates.
* Remove codgen deps from xtask, speeding-up from-source installation.
This regresses the release process a bit, as it now needs to run the
tests (and, by extension, compile the code).
9455: feat: Handle not let if expressions in replace_if_let_with_match r=Veykril a=Veykril
Transforms bare `if cond {}` into `_ if cond` guard patterns in the match as long as at least one `if let` is in the if chain, otherwise the assist wont be applicable.
bors r+
Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
9454: feat: Empower `replace_if_let_with_match` r=Veykril a=Veykril
Now instead of only working on `if let ... {} else {}` if expressions it now works on all of them where the condition expression is the same text-wise.
This includes if let expressions without an else block, in which case a simple `_ => ()` will be generated in the resulting match but also in more complex cases where multiple `if let` expressions are chained.
bors r+
Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
9450: internal: Add ModuleOrItem guess to import granularity guessing r=Veykril a=Veykril
I think this should be the last fix needed for this(🤞)
bors r+
Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
9334: feat: Allow to disable import insertion on single path glob imports r=Veykril a=Veykril
On by default as I feel like this is something the majority would prefer.
Closes#8490
Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
9321: Inline generics in const and function trait completions r=Veykril a=RDambrosio016
This PR does a couple of things:
- moves path_transform from ide_assists to ide_db to be shared by both assists and completions
- when completing a const or a function for a trait, it will "inline" any generics in those associated items instead
of leaving the generic's name. For example:
```rust
trait Foo<T> {
const BAR: T;
fn foo() -> T;
}
struct Bar;
impl Foo<u32> for Bar {
// autocompletes to this
fn foo() -> u32;
// and not this (old)
fn foo() -> T;
// also works for associated consts and where clauses
const BAR: u32 = /* */
}
```
Currently this does not work for const generics, because `PathTransform` does not seem to account for them. If this should work on const generics too, `PathTransform` will need to be changed. However, it is uncommon to implement a trait only for a single const value, so this isnt a huge concern.
Co-authored-by: rdambrosio <rdambrosio016@gmail.com>