internal: clean and enhance readability for `generate_delegate_trait`
Continue from #16112
This PR primarily involves some cleanup and simple refactoring work, including:
- Adding numerous comments to layer the code and explain the behavior of each step.
- Renaming some variables to make them more sensible.
- Simplify certain operations using a more elegant approach.
The goal is to make this intricate implementation clearer and facilitate future maintenance.
In addition to this, the PR also removes redundant `path_transform` operations for `type_gen_args`.
Taking the example of `impl Trait<T1> for S<S1>`, where `S1` is considered. The struct `S` must be in the file where the user triggers code actions, so there's no need for the `path_transform`. Furthermore, before performing the transform, we've already renamed `S1`, ensuring it won't clash with existing generics parameters. Therefore, there's no need to transform it.
* Extracted the function `for_unique_generic_name` that handling generics with identical names for reusability.
* Renamed `for_generic_params` to `for_impl_trait_as_generic` for clarity
* Added documentations for `for_impl_trait_as_generic` and `for_unique_generic_name`
fix: rewrite code_action `generate_delegate_trait`
I've made substantial enhancements to the "generate delegate trait" code action in rust-analyzer. Here's a summary of the changes:
#### Resolved the "Can’t find CONST_ARG@158..159 in AstIdMap" error
Fix#15804, fix#15968, fix#15108
The issue stemmed from an incorrect application of PathTransform in the original code. Previously, a new 'impl' was generated first and then transformed, causing PathTransform to fail in locating the correct AST node, resulting in an error. I rectified this by performing the transformation before generating the new 'impl' (using make::impl_trait), ensuring a step-by-step transformation of associated items.
#### Rectified generation of `Self` type
`generate_delegate_trait` is unable to properly handle trait with `Self` type.
Let's take the following code as an example:
```rust
trait Trait {
fn f() -> Self;
}
struct B {}
impl Trait for B {
fn f() -> B { B{} }
}
struct S {
b: B,
}
```
Here, if we implement `Trait` for `S`, the type of `f` should be `() -> Self`, i.e. `() -> S`. However we cannot automatically generate a function that constructs `S`.
To ensure that the code action doesn't generate delegate traits for traits with Self types, I add a function named `has_self_type` to handle it.
#### Extended support for generics in structs and fields within this code action
The former version of `generate_delegate_trait` cannot handle structs with generics properly. Here's an example:
```rust
struct B<T> {
a: T
}
trait Trait<T> {
fn f(a: T);
}
impl<T1, T2> Trait<T1> for B<T2> {
fn f(a: T1) -> T2 { self.a }
}
struct A {}
struct S {
b$0 : B<A>,
}
```
The former version will generates improper code:
```rust
impl<T1, T2> Trait<T1, T2> for S {
fn f(&self, a: T1) -> T1 {
<B as Trait<T1, T2>>::f( &self.b , a)
}
}
```
The rewritten version can handle generics properly:
```rust
impl<T1> Trait<T1> for S {
fn f(&self, a: T1) -> T1 {
<B<A> as Trait<T1>>::f(&self.b, a)
}
}
```
See more examples in added unit tests.
I enabled support for generic structs in `generate_delegate_trait` through the following steps (using the code example provided):
1. Initially, to prevent conflicts between the generic parameters in struct `S` and the ones in the impl of `B`, I renamed the generic parameters of `S`.
2. Then, since `B`'s parameters are instantiated within `S`, the original generic parameters of `B` needed removal within `S` (to avoid errors from redundant parameters). An important consideration here arises when Trait and B share parameters in `B`'s impl. In such cases, these shared generic parameters cannot be removed.
3. Next, I addressed the matching of types between `B`'s type in `S` and its type in the impl. Given that some generic parameters in the impl are instantiated in `B`, I replaced these parameters with their instantiated results using PathTransform. For instance, in the example provided, matching `B<A>` and `B<T2>`, where `T2` is instantiated as `A`, I replaced all occurrences of `T2` in the impl with `A` (i.e. apply the instantiated generic arguments to the params).
4. Finally, I performed transformations on each assoc item (also to prevent the initial issue) and handled redundant where clauses.
For a more detailed explanation, please refer to the code and comments. I welcome suggestions and any further questions!
fix: self type replacement in inline-function
Fix#16113, fix#16091
The problem described in this issue actually involves three bugs.
Firstly, when using `ted` to modify the syntax tree, the offset of nodes on the tree changes, which causes the syntax range information from `hir` to become invalid. Therefore, we need to edit the AST after the last usage for `usages_for_locals`.
The second issue is that when inserting nodes, it's necessary to use `clone_subtree` for duplication because the `ted::replace` operation essentially moves a node.
The third issue is that we should use `ancestors_with_macros` instead of `ancestors` to handle impl definition in macros.
I have fixed the three bugs mentioned above and added unit tests.
internal: Migrate assists to the structured snippet API, part 5
Continuing from #15874
Migrates the following assists:
- `extract_variable`
- `generate_function`
- `replace_is_some_with_if_let_some`
- `replace_is_ok_with_if_let_ok`
fix: no code action 'introduce_named_generic' for impl inside types
Fix#15734.
### Changes Made
- Find params in `ancestors` instead of just `parent`
- Added tests (`replace_impl_with_mut` and `replace_impl_inside`)
Fix incorrectly replacing references in macro invocation in "Convert to named struct" assist
Fixes#15630.
Complements #13647 (same assist but missed this one), #14920 (inverse action assist).
fix: resolve Self type references in delegate method assist
This PR makes the delegate method assist resolve any `Self` type references in the parameters or return type. It also works across macros such as the `uint_impl!` macro used for `saturating_mul` in the issue example.
Closes#14485