fix: format expression parsing edge-cases
- Handle positional arguments with formatting options (i.e. `{:b}`). Previously copied `:b` as an argument, producing broken code.
- Handle indexed positional arguments (`{0}`) ([reference](https://doc.rust-lang.org/std/fmt/#positional-parameters)). Previously copied over `0` as an argument.
Note: the assist also breaks when named arguments are used (`"{name}$0", name = 2 + 2` is converted to `"{}"$0, name`. I'm working on fix for that as well.
Feat: extracted method from trait impl is placed in existing impl
**Before**
https://user-images.githubusercontent.com/1759192/183872883-3b0eafd2-d1dc-440e-9e66-38e3372f8b64.mp4
**After**
https://user-images.githubusercontent.com/1759192/183875769-87f34c7d-52f0-4dfc-9766-f591ee738ebb.mp4
Previously, when triggering a method extraction from within an impl trait block, then this would always create a new impl block for
the struct, even if there already is one. Now, if there is already an existing trait-less impl block, then it'll put the extracted method in there.
**Caveats**:
- It currently requires the target impl block to be non-empty. This limitation is because the current architecture takes a `node_to_insert_after` as reference for where to insert the extracted function. An empty impl block doesn't have such a reference node, since it's empty. It seems that supporting this requires a much larger and more complex change.
- This is my first contribution in rust, so apologies for any beginner mistakes.
internal: Migrate `ide_assists::utils` and `ide_assists::handlers` to use format arg captures (part 1)
This not only serves as making future migration to mutable syntax trees easier, it also finds out what needs to be migrated in the first place.
~~Aside from the first commit, subsequent commits are structured to only deal with one file/handler at a time.~~
This is the first of 3 PRs, migrating:
Utils:
- `gen_trait_fn_body`
- `render_snippet`
- `ReferenceConversion`
- `convert_type`
- `getter`
Handlers:
- `add_explicit_type`
- `add_return_type`
- `add_turbo_fish`
- `apply_demorgan`
- `auto_import`
- `convert_comment_block`
- `convert_integer_literal`
- `convert_into_to_from`
- `convert_iter_for_each_to_for`
- `convert_let_else_to_match`
- `convert_tuple_struct_to_named_struct`
- `convert_two_arm_bool_match_to_matches_macro`
- `destructure_tuple_binding`
- `extract_function`
- `extract_module`
- `extract_struct_from_enum_variant`
- `extract_type_alias`
- `extract_variable`
- `fix_visibility`
feat: add config for inserting must_use in `generate_enum_as_method`
Should fix#13312
Didn't add a test because I was not sure on how to add test for a specific configuration option, tried to look for the usages for other `AssistConfig` variants but couldn't find any in `tests`. If there is a way to test this, do point me towards it.
I tried to extract the formatting string as a common `template_string` and only have if-else for that, but it didn't compile :(
Also it seems these tests are failing:
```
test config::tests::generate_config_documentation ... FAILED
test config::tests::generate_package_json_config ... FAILED
```
Can you also point me to how to correct these 😅 ( I guess there is some command to automatically generate these? )
Add convert_named_struct_to_tuple_struct assist
Closes#11643, since the assist for converting in the other direction is already there (I based most of the implementation and all of the tests on it).
Restructure `find_path` into a separate functions for modules and non-module items
Follow up to https://github.com/rust-lang/rust-analyzer/pull/13212
Also renames `prefer_core` imports config to `prefer_no_std` and changes the behavior of no_std path searching by preferring `core` paths `over` alloc
This PR turned into a slight rewrite, so it unfortunately does a few more things that I initially planned to (including a bug fix for enum variant paths)
New assist: move_format_string_arg
The name might need some improving.
```rust
fn main() {
print!("{x + 1}");
}
```
to
```rust
fn main() {
print!("{}"$0, x + 1);
}
```
fixes#13180
ref to #5988 for similar work
* extracted `format_like`'s parser to it's own module in `ide-db`
* reworked the parser's API to be more direct
* added assist to extract expressions in format args
The name might need some improving.
extract format_like's parser to it's own module in ide-db
reworked the parser's API to be more direct
added assist to extract expressions in format args
feature: Assist to turn match into matches! invocation
Resolves#12510
This PR adds an assist, which convert 2-arm match that evaluates to a boolean into the equivalent matches! invocation.
fix: Only move comments when extracting a struct from an enum variant
Motivating example:
```rs
#[derive(Debug, thiserror::Error)]
enum Error {
/// Some explanation for this error
#[error("message")]
$0Woops {
code: u32
}
}
```
now becomes
```rs
/// Some explanation for this error
#[derive(Debug, thiserror::Error)]
struct Woops{
code: u32
}
#[derive(Debug, thiserror::Error)]
enum Error {
#[error("message")]
Woops(Woops)
}
```
(the `thiserror::Error` derive being copied and the struct formatting aren't ideal, though those are issues for another day)
Use correct type in "Replace turbofish with type"
And support `?` and `.await` expressions.
Fixes#13148.
The assist can still show up even if the turbofish's type is not used at all, e.g.:
```rust
fn foo<T>() {}
let v = foo::<i32>();
```
I implemented that by checking the expressions' type.
This could probably be implemented better by taking the function's return type and substituting the generic parameter with the provided turbofish, but this is more complicated.
feat: Generate static method using Self::assoc() syntax
This change improves the `generate_function` assist to support generating static methods/associated functions using the `Self::assoc()` syntax. Previously, one could generate a static method, but only when specifying the type name directly (like `Foo::assoc()`). After this change, `Self` is supported as well as the type name.
Fixes#13012
feat: Add an assist for inlining all type alias uses
## Description
`inline_type_alias_uses` assist tries to inline all selected type alias occurrences.
### Currently
Type alias used in `PathType` position are inlined.
### Not supported
- Removing type alias declaration if all uses are inlined.
- Removing redundant imports after inlining all uses in the file.
- Type alias not in `PathType` position, such as:
- `A::new()`
- `let x = A {}`
- `let bits = A::BITS`
- etc.
## Demonstration
![example](https://user-images.githubusercontent.com/45790125/184905226-9cb8ac81-1439-4387-a13b-e18ad4ecf208.gif)
## Related Issues
Partially fixes#10881
This PR will fix some typos detected by [typos].
There are also some other typos in the function names, variable names, and file
names, which I leave as they are. I'm more certain that typos in comments
should be fixed.
[typos]: https://github.com/crate-ci/typos
This change improves the `generate_function` assist to support generating static methods/associated functions using the `Self::assoc()` syntax. Previously, one could generate a static method, but only when specifying the type name directly (like `Foo::assoc()`). After this change, `Self` is supported as well as the type name.
Fixes#13012
Previously, when triggering a method extraction from within a trait
impl block, then this would always create a new impl block for
the struct, even if there already is one. Now, it'll put the extracted
method in the matching existing block if it exists.
fix: don't replace default members' body
cc #12779, #12821
addresses https://github.com/rust-lang/rust-analyzer/pull/12821#issuecomment-1190157506
`gen_trait_fn_body()` only attempts to implement required trait member functions, so we shouldn't call it for `Implement default members` assist.
This patch also documents the precondition of `gen_trait_fn_body()` and inserts `debug_assert!`, but I'm not entirely sure if the assertions are appropriate.
fix: Insert `pub(crate)` after doc comments and attribute macros
Fixes#12790
Original behavior was to insert `pub(crate)` at the `first_child_or_token`, which for an item with a comment or attribute macro, would put the visibility marker before the comment or macro, instead of after.
This merge request alters the call to find the node with appropriate `SyntaxKind` in the `children_or_tokens`. It also adds a test case to the module to verify the behavior. Test case verifies function, module, records, enum, impl, trait, and type cases.
fix: Prevent panic in Remove Unused Parameter assist
Instead of calling `builder.delete` for every text range we find with
`process_usage`, we now ensure that the ranges do not overlap before removing
them. If a range is fully contained by a prior one, it is dropped.
fixes#12784
Instead of calling `builder.delete` for every text range we find with
`process_usage`, we now ensure that the ranges do not overlap before removing
them. If a range is fully contained by a prior one, it is dropped.
fixes#12784
Fix extract variable assist for subexpression in mutable borrow
This checks if the expression is in a mutable borrow and if so makes the extracted variable `mut`.
Closes#12786
Automatically instaciate trivially instaciable structs in "Generate new" and "Fill struct fields"
As proposed in #12535 this PR changes the "Generate new" and "Fill struct fields" assist/diagnostic to instanciate structs with no fields and enums with a single empty variant.
For example:
```rust
pub enum Bar {
Bar {},
}
struct Foo<T> {
a: usize,
bar: Bar,
_phantom: std::marker::PhantomData<T>,
}
impl<T> Foo<T> {
/* generate new */
fn random() -> Self {
Self { /* Fill struct fields */ }
}
}
```
was previously:
```rust
impl<T> Foo<T> {
fn new(a: usize, bar: Bar, _phantom: std::marker::PhantomData<T>) -> Self {
Self { a, bar, _phantom }
}
fn random() -> Self {
Self {
a: todo!(),
bar: todo!(),
_phantom: todo!(),
}
}
}
```
and is now:
```rust
impl<T> Foo<T> {
fn new(a: usize) -> Self {
Self {
a,
bar: Bar::Bar {},
_phantom: std::marker::PhantomData
}
}
fn random() -> Self {
Self {
a: todo!(),
bar: Bar::Bar {},
_phantom: std::marker::PhantomData,
}
}
}
```
I'd be happy about any suggestions.
## TODO
- [x] deduplicate `use_trivial_constructor` (unclear how to do as it's used in two separate crates)
- [x] write tests
Closes#12535
fix: Support generics in extract_function assist
This change attempts to resolve issue #7636: Extract into Function does not
create a generic function with constraints when extracting generic code.
In `FunctionBody::analyze_container`, we now traverse the `ancestors` in search
of `AnyHasGenericParams`, and attach any `GenericParamList`s and `WhereClause`s
we find to the `ContainerInfo`.
Later, in `format_function`, we collect all the `GenericParam`s and
`WherePred`s from the container, and filter them to keep only types matching
`TypeParam`s used within the newly extracted function body or param list. We
can then include the new `GenericParamList` and `WhereClause` in the new
function definition.
This change only impacts `TypeParam`s. `LifetimeParam`s and `ConstParam`s are
out of scope for this change.
I've never contributed to this project before, but I did try to follow the style guide. I believe that this change represents an improvement over the status quo, but I think it's also fair to argue that it doesn't fully "fix" the linked issue. I'm totally open to merging this as is, or going further to try to make a more complete solution. Also: if there are other unit or integration tests I should add, please let me know where to look!
This change attempts to resolve issue #7636: Extract into Function does not
create a generic function with constraints when extracting generic code.
In `FunctionBody::analyze_container`, we now traverse the `ancestors` in search
of `AnyHasGenericParams`, and attach any `GenericParamList`s and `WhereClause`s
we find to the `ContainerInfo`.
Later, in `format_function`, we collect all the `GenericParam`s and
`WherePred`s from the container, and filter them to keep only types matching
`TypeParam`s used within the newly extracted function body or param list. We
can then include the new `GenericParamList` and `WhereClause` in the new
function definition.
This change only impacts `TypeParam`s. `LifetimeParam`s and `ConstParam`s are
out of scope for this change.
When extracting a field expression, if RA was unable to resolve the type of the
field, we would previously fall back to using "var_name" as the variable name.
Now, when the `Expr` being extracted matches a `FieldExpr`, we can use the
`NameRef`'s ident token as a fallback option.
fixes#10035
This change fixes#12705.
In `FunctionBody::analyze`, we need to search any `ClosureExpr`s we encounter
for any `NameRef`s, to ensure they aren't missed.
fix: Extract function from trait impl
This change fixes#10036, "Extract to function assist implements nonexistent
trait methods".
When we detect that the extraction is coming from within a trait impl, and that
a `self` param will be necessary, we adjust which `SyntaxNode` to `insert_after`,
and create a new empty `impl` block for the newly extracted function.
This change fixes#10036, "Extract to function assist implements nonexistent
trait methods".
When we detect that the extraction is coming from within a trait impl, and that
a `self` param will be necessary, we adjust which `SyntaxNode` to `insert_after`,
and create a new empty `impl` block for the newly extracted function.
This change fixes issue #10037, in more or less the most naive fashion
possible.
We continue to start with the hardcoded default of "fun_name", and now append a
counter to the end of it if that name is already in scope.
In the future, we can probably apply more heuristics here to wind up with more
useful names by default, but for now this resolves the immediate problem.
Order auto-imports by relevance
Fixes#10337.
Basically we sort the imports according to how "far away" the imported item is from where we want to import it to. This change makes it so that imports from the current crate are sorted before any third-party crates. Additionally, we make an exception for builtin crates (`std`, `core`, etc.) so that they are sorted before any third-party crates.
There are probably other heuristics that should be added to improve the experience (such as preferring imports that are common elsewhere in the same crate, and ranking crates depending on the dependency graph). However, I think this is a first good step.
PS. This is my first time contributing here, so please be gentle if I have missed something obvious :-)
The selected imports have to have a common prefix in paths.
Before
```rust
$0use std::fmt::Display;
use std::fmt::Debug;$0
```
After
```rust
use std::fmt::{Display, Debug};
```
fix(extract_module) resolving import panics and improve import resolution
- Should solve #11766
- While adding a test case for this issue, I observed another issue:
For this test case:
```rust
mod x {
pub struct Foo;
pub struct Bar;
}
use x::{Bar, Foo};
$0type A = (Foo, Bar);$0
```
extract module should yield this:
```rust
mod x {
pub struct Foo;
pub struct Bar;
}
use x::{};
mod modname {
use super:❌:Bar;
use super:❌:Foo;
pub(crate) type A = (Foo, Bar);
}
```
instead it gave:
```rust
mod x {
pub struct Foo;
pub struct Bar;
}
use x::{};
mod modname {
use x::Bar;
use x::Foo;
pub(crate) type A = (Foo, Bar);
}
```
So fixed this problem with second commit
This also disables "generate function" when what we clearly want is to
generate an enum variant.
Co-authored-by: Maarten Flippo <maartenflippo@outlook.com>