Commit Graph

327 Commits

Author SHA1 Message Date
bors[bot]
88e8b0a5fa
Merge #7620
7620: Support control flow in `extract_function` assist r=matklad a=cpud36

Support `return`ing from outer function, `break`ing and `continue`ing outer loops when extracting function.

# Example
Transforms
```rust
fn foo() -> i32 {
  let items = [1,2,3];
  let mut sum = 0;
  for &item in items {
    <|>if item == 42 {
      break;
    }<|>
    sum += item;
  }
  sum
}
```
Into 
```rust
fn foo() -> i32 {
  let items = [1,2,3];
  let mut sum = 0;
  for &item in items {
    if fun_name(item) {
      break;
    }
    sum += item;
  }
  sum
}

fn fun_name(item: i32) -> bool {
  if item == 42 {
    return true;
  }
  false
}
```

![add_explicit_type_infer_type](https://user-images.githubusercontent.com/4218373/107544222-0fadf280-6bdb-11eb-9625-ed6194ba92c0.gif)

# Features

Supported variants
- break and function does not return => uses `bool` and plain if
- break and function does return => uses `Option<T>` and matches on it
- break with value and function does not return => uses `Option<T>` and if let
- break with value and function does return => uses `Result<T, U>` and matches on t
- same for `return` and `continue`(but we can't continue with value)

Assist does handle nested loops and nested items(like functions, modules, impls)

Try `expr?` operator is allowed together with `return Err(_)` and `return None`.
`return expr` is not allowed.

# Not supported
## Mixing `return` with `break` or `continue`
If we have e.g. a `return` and a `break` in the selected code, it is unclear what the produced code should look like.
We can try `Result<T, Option<U>>` or something like that, but it isn't idiomatic, nor it is established. Otherwise, implementation
is relatively simple.

## `break` with label
Not sure how to handle different labels for multiple `break`s.

[edit] implemented try `expr?`

Co-authored-by: Vladyslav Katasonov <cpud47@gmail.com>
2021-02-16 14:01:09 +00:00
bors[bot]
a0322defc3
Merge #7656
7656: Implement constructor usage search for almost all items r=matklad a=Veykril

This PR moves the filering for enum constructors to the HIR, with this unprefixed variants as well as when the enum has been renamed via use will then still show up properly.
We now walk the ast of the `NameRef` up until we find a `PathExpr`(which also handles `CallExpr` for tuple-type structs and variants already) or a `RecordExpr`. For enum search we then take the `path` out of that expression and do a resolution on it to compare it with the definition enum.
With this PR we now support searching for all constructor literals, Unit-, Tuple- and Record-Structs, Unit-, Tuple- and Record-Variants as well as Unions.

There is one shortcoming due to how the search is triggered. Unit Variants constructors can't be searched as we have no position for it to kick off the search(since a comma doesn't have to exist for the last variant).

Closes #2549 though it doesn't implement it as outlined in the issue since the reference kind was removed recently, though I believe the approach taken here is better personally.

Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
2021-02-14 16:17:03 +00:00
Domantas Jadenkus
150ed80c51 strip type parameter defaults when generating impl generics 2021-02-13 23:59:51 +02:00
Domantas Jadenkus
7f100fff92 cargo fmt 2021-02-13 22:51:48 +02:00
Domantas Jadenkus
36e8a55bee use generate_impl_text in replace_derive_with_manual_impl 2021-02-13 22:51:07 +02:00
Domantas Jadenkus
3364ac8b11 use generate_impl_text in generate_impl 2021-02-13 22:45:22 +02:00
Domantas Jadenkus
ff7ea7c308 use generate_impl_text in generate_from_impl 2021-02-13 22:27:57 +02:00
Vladyslav Katasonov
37a8cec638 expose hir::Type::type_paramters
Used to get E parameter from `Result<T, E>`
2021-02-13 22:04:52 +03:00
Vladyslav Katasonov
4be260d693 allow try expr? with return None in extracted function 2021-02-13 22:04:52 +03:00
Vladyslav Katasonov
9eb19d92dd allow try expr? when extacting function 2021-02-13 22:04:52 +03:00
Vladyslav Katasonov
f345d1772a handle return, break and continue when extracting function 2021-02-13 22:04:52 +03:00
Vladyslav Katasonov
0ad3d7938f migrate body span to {parent,text_range}
This simplifies api as we are not duplicating code from syntax crate
2021-02-13 22:04:52 +03:00
Lukas Wirth
ed1f2b58f7 Group generate getter/setter assist 2021-02-13 19:58:58 +01:00
Domantas Jadenkus
b07f530e3a cargo fmt 2021-02-13 15:34:40 +02:00
Domantas Jadenkus
375c13cd44 make it work for record-style variants 2021-02-13 14:57:06 +02:00
Domantas Jadenkus
6799088579 update doc 2021-02-13 14:46:41 +02:00
Domantas Jadenkus
3a4d273ac2 handle generic enums 2021-02-13 14:46:28 +02:00
Domantas Jadenkus
e63116c74f allow any field type 2021-02-13 14:29:26 +02:00
Domantas Jadenkus
fee05b0491 use Self instead of enum name 2021-02-13 14:27:38 +02:00
Lukas Wirth
c395dd1032 Implement constructor usage search for almost all items
For all struct kinds, unions and enums, as well as for record- and
tuple-variants but not for unit-variants, as these have no trailing
character we can anchor the search to. Functionality wise it is
implemented though.
2021-02-12 21:30:55 +01:00
Lukas Wirth
c5be0b2589 Use NameLike in FileReference directly as its not exported from ide anymore 2021-02-12 18:58:29 +01:00
Lukas Wirth
d644728d82 Refactor reference searching to work with the ast 2021-02-12 18:58:28 +01:00
Yoshua Wuyts
ac959b82b3 Add find_impl_block_end assist helper 2021-02-12 17:59:08 +01:00
bors[bot]
5e39d7a680
Merge #7617
7617: Add getter/setter assists r=Veykril a=yoshuawuyts

This patch makes progress towards the design outlined in https://github.com/rust-analyzer/rust-analyzer/issues/5943, and includes a small refactor which closes https://github.com/rust-analyzer/rust-analyzer/issues/7607. All together this patch does 4 things:

- Adds a `generate_getter` assist.
- Adds a `generate_getter_mut` assist.
- Adds a `generate_setter` assist.
- Moves the `generate_impl_text` function from `generate_new` into `utils` (which closes #7607).

## Design Notes

I've chosen to follow the [Rust API guidelines on getters](https://rust-lang.github.io/api-guidelines/naming.html#getter-names-follow-rust-convention-c-getter) as closely as possible. This deliberately leaves "builder pattern"-style setters out of scope.

Also, similar to https://github.com/rust-analyzer/rust-analyzer/pull/7570 this assist generates doc comments. I think this should work well in most cases, and for the few where it doesn't it's probably easily edited. This makes it slightly less correct than the #7570 implementation, but I think this is still useful enough to include for many of the same reasons.

The reason why this PR contains 3 assists, rather than 1, is because each of them is so similar to the others that it felt more noisy to do them separately than all at once. The amount of code added does not necessarily reflect that, but hope that still makes sense.

## Examples

**Input**
```rust
struct Person {
    name: String,     // <- cursor on "name"
}
```

**generate getter**
```rust
struct Person {
    name: String,
}

impl Person {
    /// Get a reference to the person's name.
    fn name(&self) -> &String {
        &self.name
    }
}
```

**generate mut getter**
```rust
struct Person {
    name: String,
}

impl Person {
    /// Get a mutable reference to the person's name.
    fn name_mut(&mut self) -> &mut String {
        &mut self.name
    }
}
```

**generate setter**
```rust
struct Person {
    name: String,
}

impl Person {
    /// Set the person's name.
    fn set_name(&mut self, name: String) {
        self.name = name;
    }
}
```


Co-authored-by: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
2021-02-10 10:32:36 +00:00
Yoshua Wuyts
bfa99f20ff Add #[track_caller] to assist tests 2021-02-10 00:16:00 +01:00
Yoshua Wuyts
e8d7bcc355 Add getter/setter assists
Finish implementing `generate_setter` assists

Make `generate_impl_text` util generic

generate getter methods

Fix getter / setter naming

It's now in-line with the Rust API naming guidelines: https://rust-lang.github.io/api-guidelines/naming.html#getter-names-follow-rust-convention-c-getter

apply clippy

Improve examples
2021-02-10 00:08:41 +01:00
Aleksey Kladov
7022ea52b5 AdtDef -> Adt 2021-02-07 14:15:02 +03:00
bors[bot]
80ab753d7e
Merge #7572
7572: Add `find_or_create_impl_block` to assist utils r=matklad a=yoshuawuyts

This is another continuation of https://github.com/rust-analyzer/rust-analyzer/pull/7562, introducing a small util to either find an `impl` block, or create a new one if none exists. I copied this code from the `generate_new` assist into https://github.com/rust-analyzer/rust-analyzer/pull/7562, and this unifies both into a helper.

It doesn't feel super polished in its current state, but my hope is that this is enough of a starting point that it can be expanded on later. For example something that would be useful would be a flag which either returns the index of the start of the block, or the end of the block.

Anyway, I hope this is useful. Thanks!

Co-authored-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2021-02-05 17:18:02 +00:00
Yoshua Wuyts
2cf1612669 Add find_or_create_impl_block to assist utils 2021-02-05 17:19:31 +01:00
bors[bot]
737e7a7b75
Merge #7574
7574: Remove various redundant clones r=kjeremy a=yoshuawuyts

I noticed when running clippy through RA that there are a few instances where `clone` is called where it's not actually needed. I figured a small patch to remove these might be welcome here.

Thanks!

Co-authored-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2021-02-05 16:04:50 +00:00
Yoshua Wuyts
79d103d5b4 Remove redundant clones 2021-02-05 16:57:26 +01:00
bors[bot]
855b00cbe6
Merge #7570 #7571
7570: Add doc gen to the `generate_enum_match_method` assist r=yoshuawuyts a=yoshuawuyts

Implements a small extension to https://github.com/rust-analyzer/rust-analyzer/pull/7562, generating default comments. I wasn't sure if this would fit the goals of Rust-Analyzer, so I chose to split it into a separate PR. This is especially useful when writing code in a codebase which uses `#![warn(missing_docs)]` lint, as many production-grade libraries do.

The comments we're generating here are similar to the ones found on [`Option::is_some`](https://doc.rust-lang.org/std/option/enum.Option.html#method.is_some) and [`Result::is_err`](https://doc.rust-lang.org/std/result/enum.Result.html#method.is_err). I briefly considered only generating these for `pub` types, but they seem small and unobtrusive enough that they're probably useful in the general case. Thanks!

## Example

__input__
```rust
pub(crate) enum Variant {
    Undefined,
    Minor, // cursor here
    Major,
}
```

__output__
```rust
pub(crate) enum Variant {
    Undefined,
    Minor,
    Major,
}

impl Variant {
    /// Returns `true` if the variant is [`Minor`].
    pub(crate) fn is_minor(&self) -> bool {
        matches!(self, Self::Minor)
    }
}
```

## Future Directions

This opens up the path to adding an assist for generating these comments on existing `is_` methods. This would make it both easy to document new code, and update existing code with documentation.

7571: Cleanup decl_check r=Veykril a=Veykril

bors r+

Co-authored-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
2021-02-05 15:17:41 +00:00
Yoshua Wuyts
d90bd63536 Add doc gen to the generate_enum_match_method assist 2021-02-05 16:00:07 +01:00
bors[bot]
b89fef5220
Merge #7562
7562: add `generate_enum_match` assist r=matklad a=yoshuawuyts

This adds a `generate_enum_match` assist, which generates `is_` variants for enums (e.g. `Option::{is_none,is_some}` in std). This is my first attempt at contributing to Rust-Analyzer, so I'm not sure if I've gotten everything right. Thanks!

## Example

**Input**
```rust
pub(crate) enum Variant {
    Undefined,
    Minor, // cursor here
    Major,
}
```
**Output**
```rust
pub(crate) enum Variant {
    Undefined,
    Minor,
    Major,
}

impl Variant {
    pub(crate) fn is_minor(&self) -> bool {
        matches!(self, Self::Minor)
    }
}
```

## Future Directions

I made this as a stepping stone for some of the more involved refactors (e.g. #5944). I'm not sure yet how to create, use, and test `window.showQuickPick`-based asssists in RA. But once that's possible, it'd probably be nice to be able to generate match methods in bulk through the quickpick UI rather than one-by-one:

```
[x] Select enum members to generate methods for. (3 selected) [ OK ]
---------------------------------------------------------------------------
[x] Undefined
[x] Minor
[x] Major
```

Co-authored-by: Yoshua Wuyts <yoshuawuyts+github@gmail.com>
Co-authored-by: Yoshua Wuyts <yoshuawuyts@gmail.com>
2021-02-05 14:28:25 +00:00
Yoshua Wuyts
dfd751303e Move find_struct_impl to assist utils 2021-02-05 14:36:07 +01:00
Yoshua Wuyts
13d663dd16 add generate-enum-match assist 2021-02-05 11:28:11 +01:00
bors[bot]
ac5958485e
Merge #7535
7535: Extract function assist r=cpud36 a=cpud36

This PR adds `extract function/method` assist. closes #5409.

# Supported features
Assist should support extracting from expressions(`1`, `2 + 2`, `loop { }`) and from a series of statements, e.g.:
```rust
foo();
$0bar();
baz();$0
quix();
```
Assist also supports extracting parameters, like:
```rust
fn foo() -> i32 {
  let n = 1;
  $0n + 1$0
}

// -
fn foo() -> i32 {
  let n = 1;
  fun_name(n)
}

fn fun_name(n: i32) -> i32 {
  n + 1
}
```

Extracting methods also generally works.

Assist allows referencing outer variables, both mutably and immutably, and handles handles access to variables local to extracted function:
```rust
fn foo() {
  let mut n = 1;
  let mut m = 2;
  let mut moved_v = Vec::new();
  let mut ref_mut_v = Vec::new();
  $0
  n += 1;
  let k = 1;
  moved_v.push(n);
  let r = &mut m;
  ref_mut_v.push(*r);
  let h = 3;
  $0
  n = ref_mut_v.len() + k;
  n -= h + m;
}

// -
fn foo() {
  let mut n = 1;
  let mut m = 2;
  let mut moved_v = Vec::new();
  let mut ref_mut_v = Vec::new();
 
  let (k, h) =  fun_name(&mut n, moved_v, &mut m, &mut ref_mut_v);

  n = ref_mut_v.len() + k;
  n -= h + m;
}

fn fun_name(n: &mut i32, mut moved_v: Vec<i32>, m: &mut i32, ref_mut_v: &mut Vec<i32>) -> (i32, i32) {
  *n += 1;
  let k = 1;
  moved_v.push(*n);
  let r = m;
  ref_mut_v.push(*r);
  let h = 3;
  (k, h)
}
```

So we handle both input and output paramters

# Showcase

![extract_cursor_in_range_3](https://user-images.githubusercontent.com/4218373/106980190-c9870800-6770-11eb-83d9-3d36b2550ff6.gif)
![fill_match_arms_discard_wildcard](https://user-images.githubusercontent.com/4218373/106980197-cbe96200-6770-11eb-96b0-14c27894fac0.gif)
![ide_db_helpers_handle_kind](https://user-images.githubusercontent.com/4218373/106980201-cdb32580-6770-11eb-9e6e-6ac8155d65ac.gif)
![ide_db_imports_location_local_query](https://user-images.githubusercontent.com/4218373/106980205-cf7ce900-6770-11eb-8516-653c8fcca807.gif)

# Working with non-`Copy` types

Consider the following example:
```rust
fn foo() {
  let v = Vec::new();
  $0
  let n = v.len();
  $0
  let is_empty = v.is_empty();
}
```
`v` must be a parameter to extracted function. 
The question is, what type should it have.
It could be `v: Vec<i32>`, or `v: &Vec<i32>`. 
The former is incorrect for `Vec<i32>`, but the later is silly for `i32`.

To resolve this we need to know if the type implements `Copy` trait.

I didn't find any api available from assists to query this. 
`hir_ty::method_resolution::implements` seems relevant, but is isn't publicly re-exported from `hir`.

# Star(`*`) token and pointer dereference

If I understand correctly, in order to create expression like `*p`, one should use `ast::make::expr_prefix(T![*], ...)`, which
in turn calls `token(T![*])`.

`token` does not have star in `tokens::SOURCE_FILE`, so this panics.
I had to add `*` to `SOURCE_FILE` to make it work.

Correct me if this is not intended way to do this.

# Lowering access `value -> mut ref -> shared ref`

Consider the following example:
```rust
fn foo() {
  let v = Vec::new();
  $0 let n = v.len(); $0
}
```
`v` is not used after extracted function body, so both `v: &Vec<i32>` and `v: Vec<i32>` would work.
Currently the later would be chosen.

We can however check the body of extracted function and conclude that `v: &Vec<i32>` is sufficient.
Using `v: &Vec<i32>`(that is a minimal required access level) might be a better default.
I am unsure.

# Cleanup
The assist seems to be reasonably handling most of common cases.
If there are no concerns with code it produces(i.e. with test cases), I will start cleaning up

[edit]
added showcase


Co-authored-by: Vladyslav Katasonov <cpud47@gmail.com>
2021-02-05 02:55:56 +00:00
Vladyslav Katasonov
7eaa3e56a0 allow extracted body to be indented(dedent it) 2021-02-05 05:44:08 +03:00
Vladyslav Katasonov
876ca60316 allow transitive &mut access for fields in extract_function 2021-02-05 04:35:41 +03:00
Vladyslav Katasonov
271c1cb013 add tests for extracting if/match/while/for exprs 2021-02-05 02:30:34 +03:00
Vladyslav Katasonov
4dc2a42500 document extract_function assist implementation 2021-02-05 02:14:32 +03:00
Vladyslav Katasonov
0ff74467c0 use &T for non copy params of extracted function
Use shared ref if param is not `T: Copy` and is used after body
2021-02-05 01:41:40 +03:00
Vladyslav Katasonov
d9b122858b split extract_function into pieces and order them 2021-02-05 00:35:28 +03:00
Jonas Schievink
5d99ba1d9a Make ModPath's representation private 2021-02-04 20:49:24 +01:00
Vladyslav Katasonov
ff77c5e68f remove ignored test for downgrading mut to shared 2021-02-04 00:52:53 +03:00
Vladyslav Katasonov
c4f3669e70 allow calling &mut methods on outer vars when extracing function 2021-02-04 00:44:36 +03:00
Vladyslav Katasonov
86ff1d4809 allow &mut param when extracting function
Recognise &mut as variable modification.
This allows extracting functions with
`&mut var` with `var` being in outer scope
2021-02-04 00:27:31 +03:00
Vladyslav Katasonov
f102616aae allow modifications of vars from outer scope inside extracted function
It currently allows only directly setting variable.
No `&mut` references or methods.
2021-02-03 23:45:03 +03:00
Vladyslav Katasonov
82787febde allow local variables to be used after extracted body
when variable is defined inside extracted body
export this variable to original scope via return value(s)
2021-02-03 21:11:12 +03:00
Vladyslav Katasonov
313aa5f3a2 change TODO to FIXME 2021-02-03 17:47:21 +03:00