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>
9108: Don't show extract into variable assist for unit expressions r=jonas-schievink a=brandondong
**Reproduction:**
```rust
fn main() {
let mut i = 3;
$0if i >= 0 {
i += 1;
} else {
i -= 1;
}$0
}
```
1. Select the snippet of code between the $0's.
2. The extract into variable assist shows up, pushing down the more useful extract into function assist.
3. The resulting output of selecting the extract into variable assist is valid but with the extracted variable having the unit type:
```rust
fn main() {
let mut i = 3;
let var_name = if i >= 0 {
i += 1;
} else {
i -= 1;
};
var_name
}
```
**Fix:**
- Don't show the extract into variable assist for unit expressions. I could not think of any scenarios where such a variable extraction would be desired.
Co-authored-by: Brandon <brandondong604@hotmail.com>
9112: Fix some bugs in `extract_struct_from_enum_variant` assist r=Veykril a=Veykril
bors r+
Fixes#9100Fixes#9099
Kind of fixes #9109, it now copies all the generics might be incorrect if the variant doesn't use all of them)
Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
8901: fix: `fill_match_arms` hangs on a tuple of large enums r=matklad a=iDawer
+ Lazy computation of missing arms.
+ Convenience function to test lazy computation: `ide_assists::tests::check_assist_unresolved`.
Fixes#8835
Co-authored-by: Dawer <7803845+iDawer@users.noreply.github.com>
8873: Implement import-granularity guessing r=matklad a=Veykril
This renames our `MergeBehavior` to `ImportGranularity` as rustfmt has it as the purpose of them are basically the same. `ImportGranularity::Preserve` currently has no specific purpose for us as we don't have an organize imports assist yet, so it currently acts the same as `ImportGranularity::Item`.
We now try to guess the import style on a per file basis and fall back to the user granularity setting if the file has no specific style yet or where it is ambiguous. This can be turned off by setting `import.enforceGranularity` to `true`.
Closes https://github.com/rust-analyzer/rust-analyzer/issues/8870
Co-authored-by: Lukas Tobias Wirth <lukastw97@gmail.com>
8813: Get some more array lengths! r=lf- a=lf-
This is built on #8799 and thus contains its changes. I'll rebase it onto master when that one gets merged. It adds support for r-a understanding the length of:
* `let a: [u8; 2] = ...`
* `let a = b"aaa"`
* `let a = [0u8; 4]`
I have added support for getting the values of byte strings, which was not previously there. I am least confident in the correctness of this part and it probably needs some more tests, as we currently have only one test that exercised that part (!).
Fixes#2922.
Co-authored-by: Jade <software@lfcode.ca>
Fix#2922: add unknown length as a condition for a type having unknown.
Incorporate reviews:
* Extract some of the const evaluation workings into functions
* Add fixmes on the hacks
* Add tests for impls on specific array lengths (these work!!! 😁)
* Add tests for const generics (indeed we don't support it yet)
8802: Keep comments and attrs when extracting struct from enum variant r=Veykril a=DropDemBits
Fixes#6730
Still unsure if existing visibilities of fields should be forced to pub (which is what was previously done), or if it's okay to keep it in the extracted struct.
Co-authored-by: DropDemBits <r3usrlnd@gmail.com>
8800: feat: Make "pull assignments up" assist work in more cases r=Jesse-Bakker a=Jesse-Bakker
Fixes#8771
Co-authored-by: Jesse Bakker <github@jessebakker.com>
There's a tension between keeping a well-architectured minimal
orthogonal set of constructs, and providing convenience functions.
Relieve this pressure by introducing an dedicated module for
non-orthogonal shortcuts.
This is inspired by the django.shortcuts module which serves a similar
purpose architecturally.
8711: Only resolve selected assist r=matklad a=SomeoneToIgnore
Part of https://github.com/rust-analyzer/rust-analyzer/issues/8700
Now resolves only the assist that was selected out of the list, while before the whole assist list was resolved despite a single popup selection.
Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
8591: Remove SyntaxRewriter usage in insert_use in favor of mutable syntax trees r=matklad a=Veykril
Unfortunately changing `insert_use` to not use `SyntaxRewriter` creates a lot of changes since so much relies on that. But on the other hand this should be the biggest usage of `SyntaxRewriter` I believe.
8638: Remove SyntaxRewriter::from_fn r=Veykril a=Veykril
Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
8620: Remove unnecessary braces for extracted block expression r=Veykril a=brandondong
This change addresses the first bullet point of https://github.com/rust-analyzer/rust-analyzer/issues/7839.
Specifically, when extracting block expressions, remove the unneeded extra braces inside the generated function.
Co-authored-by: Brandon <brandondong604@hotmail.com>
8524: Fix extract function with partial block selection r=matklad a=brandondong
**Reproduction:**
```rust
fn foo() {
let n = 1;
let mut v = $0n * n;$0
v += 1;
}
```
1. Select the snippet ($0) and use the "Extract into function" assist.
2. Extracted function is incorrect and does not compile:
```rust
fn foo() {
let n = 1;
let mut v = fun_name(n);
v += 1;
}
fn fun_name(n: i32) {}
```
3. Omitting the ending semicolon from the selection fixes the extracted function:
```rust
fn fun_name(n: i32) -> i32 {
n * n
}
```
**Cause:**
- When `extraction_target` uses a block extraction (semicolon case) instead of an expression extraction (no semicolon case), the user selection is directly used as the TextRange.
- However, the existing function extraction logic for blocks requires that the TextRange spans from start to end of complete statements to work correctly.
- For example:
```rust
fn foo() {
let m = 2;
let n = 1;
let mut v = m $0* n;
let mut w = 3;$0
v += 1;
w += 1;
}
```
produces
```rust
fn foo() {
let m = 2;
let n = 1;
let mut v = m let mut w = fun_name(n);
v += 1;
w += 1;
}
fn fun_name(n: i32) -> i32 {
let mut w = 3;
w
}
```
- The user selected TextRange is directly replaced by the function call which is now in the middle of another statement. The extracted function body only contains statements that were fully covered by the TextRange and so the `* n` code is deleted. The logic for calculating variable usage and outlived variables for the function parameters and return type respectively search within the TextRange and so do not include `m` or `v`.
**Fix:**
- Only extract full statements when using block extraction. If a user selected part of a statement, extract that full statement.
8527: Switch introduce_named_lifetime assist to use mutable syntax tree r=matklad a=iDawer
This extends `GenericParamsOwnerEdit` trait with `get_or_create_generic_param_list` method
Co-authored-by: Brandon <brandondong604@hotmail.com>
Co-authored-by: Dawer <7803845+iDawer@users.noreply.github.com>
8565: Fill match arms assist: add remaining arms for tuple of enums r=iDawer a=iDawer
Fix for #8493
However, the assist is still flaky and does not use `hir_ty::diagnostics::match_check`
Co-authored-by: Dawer <7803845+iDawer@users.noreply.github.com>
8467: Adds impl Deref assist r=jhgg a=jhgg
This PR adds a new `generate_deref` assist that automatically generates a deref impl for a given struct field.
Check out this gif:
![2021-04-11_00-33-33](https://user-images.githubusercontent.com/5489149/114296006-b38e1000-9a5d-11eb-9112-807c01b8fd0a.gif)
--
I have a few Q's:
- [x] Should I write more tests, if so, what precisely should I test for?
- [x] I have an inline question on line 65, can someone provide guidance? :)
- [x] I can implement this for `ast::TupleField` too. But should it be a separate assist fn, or should I try and jam both into the `generate_deref`?
- [x] I want to follow this up with an assist on `impl $0Deref for T {` which would automatically generate a `DerefMut` impl that mirrors the Deref as well, however, I could probably use some pointers on how to do that, since I'll have to reach into the ast of `fn deref` to grab the field that it's referencing for the `DerefMut` impl.
Co-authored-by: jake <jh@discordapp.com>
8415: Fix faulty assertion when extracting function with macro call r=matklad a=brandondong
**Reproduction:**
```rust
fn main() {
let n = 1;
let k = n * n;
dbg!(n);
}
```
1. Select the second and third lines of the main function. Use the "Extract into function" code assist.
2. Panic occurs in debug, error is logged in release: "[ERROR ide_assists::handlers::extract_function] assertion failed: matches!(path, ast :: Expr :: PathExpr(_))".
3. Function generates successfully on release where the panic was bypassed.
```rust
fn fun_name(n: i32) {
let k = n * n;
dbg!(n);
}
```
**Cause:**
- The generated function will take `n` as a parameter. The extraction logic needs to search the usages of `n` to determine whether it is used mutably or not. The helper `path_element_of_reference` is called for each usage but the second usage is a macro call and fails the `Expr::PathExpr(_)` match assertion.
- The caller of `path_element_of_reference` does implicitly assume it to be a `Expr::PathExpr(_)` in how it looks at its parent node for determining whether it is used mutably. This logic will not work for macros.
- I'm not sure if there are any other cases besides macros where it could be something other than a `Expr::PathExpr(_)`. I tried various examples and could not find any.
**Fix:**
- Update assertion to include the macro case.
- Add a FIXME to properly handle checking if a macro usage requires mutable access. For now, return false instead of running the existing logic that is tailored for `Expr::PathExpr(_)`'s.
Co-authored-by: Brandon <brandondong604@hotmail.com>
8436: Fix extract function's mutability of variables outliving the body r=matklad a=brandondong
**Reproduction:**
```rust
fn main() {
let mut k = 1;
let mut j = 2;
j += 1;
k += j;
}
```
1. Select the first to third lines of the main function. Use the "Extract into function" code assist.
2. The output is the following which does not compile because the outlived variable `k` is declared as immutable:
```rust
fn main() {
let (k, j) = fun_name();
k += j;
}
fn fun_name() -> (i32, i32) {
let mut k = 1;
let mut j = 2;
j += 1;
(k, j)
}
```
3. We would instead expect the output to be:
```rust
fn main() {
let (mut k, j) = fun_name();
k += j;
}
```
**Fix:**
- Instead of declaring outlived variables as immutable unconditionally, check for any mutable usages outside of the extracted function.
Co-authored-by: Brandon <brandondong604@hotmail.com>