Merge #2071
2071: generate more assists docs r=matklad a=matklad Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
54d1a58281
@ -1,5 +1,3 @@
|
||||
//! FIXME: write short doc here
|
||||
|
||||
use hir::db::HirDatabase;
|
||||
use ra_syntax::{
|
||||
ast::{self, AstNode, AttrsOwner},
|
||||
@ -9,6 +7,22 @@
|
||||
|
||||
use crate::{Assist, AssistCtx, AssistId};
|
||||
|
||||
// Assist: add_derive
|
||||
// Adds a new `#[derive()]` clause to a struct or enum.
|
||||
// ```
|
||||
// struct Point {
|
||||
// x: u32,
|
||||
// y: u32,<|>
|
||||
// }
|
||||
// ```
|
||||
// ->
|
||||
// ```
|
||||
// #[derive()]
|
||||
// struct Point {
|
||||
// x: u32,
|
||||
// y: u32,
|
||||
// }
|
||||
// ```
|
||||
pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
|
||||
let nominal = ctx.node_at_offset::<ast::NominalDef>()?;
|
||||
let node_start = derive_insertion_offset(&nominal)?;
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! FIXME: write short doc here
|
||||
|
||||
use hir::{db::HirDatabase, HirDisplay, Ty};
|
||||
use ra_syntax::{
|
||||
ast::{self, AstNode, LetStmt, NameOwner},
|
||||
@ -8,7 +6,19 @@
|
||||
|
||||
use crate::{Assist, AssistCtx, AssistId};
|
||||
|
||||
/// Add explicit type assist.
|
||||
// Assist: add_explicit_type
|
||||
// Specify type for a let binding
|
||||
// ```
|
||||
// fn main() {
|
||||
// let x<|> = 92;
|
||||
// }
|
||||
// ```
|
||||
// ->
|
||||
// ```
|
||||
// fn main() {
|
||||
// let x: i32 = 92;
|
||||
// }
|
||||
// ```
|
||||
pub(crate) fn add_explicit_type(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
|
||||
let stmt = ctx.node_at_offset::<LetStmt>()?;
|
||||
let expr = stmt.initializer()?;
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! FIXME: write short doc here
|
||||
|
||||
use format_buf::format;
|
||||
use hir::db::HirDatabase;
|
||||
use join_to_string::join;
|
||||
@ -10,6 +8,23 @@
|
||||
|
||||
use crate::{Assist, AssistCtx, AssistId};
|
||||
|
||||
// Assist: add_impl
|
||||
// Adds a new inherent impl for a type
|
||||
// ```
|
||||
// struct Ctx<T: Clone> {
|
||||
// data: T,<|>
|
||||
// }
|
||||
// ```
|
||||
// ->
|
||||
// ```
|
||||
// struct Ctx<T: Clone> {
|
||||
// data: T,
|
||||
// }
|
||||
//
|
||||
// impl<T: Clone> Ctx<T> {
|
||||
//
|
||||
// }
|
||||
// ```
|
||||
pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
|
||||
let nominal = ctx.node_at_offset::<ast::NominalDef>()?;
|
||||
let name = nominal.name()?;
|
||||
|
@ -1,5 +1,3 @@
|
||||
//! FIXME: write short doc here
|
||||
|
||||
use hir::{db::HirDatabase, HasSource};
|
||||
use ra_syntax::{
|
||||
ast::{self, edit, make, AstNode, NameOwner},
|
||||
@ -14,6 +12,32 @@ enum AddMissingImplMembersMode {
|
||||
NoDefaultMethods,
|
||||
}
|
||||
|
||||
// Assist: add_impl_missing_members
|
||||
// Adds scaffold for required impl members
|
||||
// ```
|
||||
// trait T {
|
||||
// Type X;
|
||||
// fn foo(&self);
|
||||
// fn bar(&self) {}
|
||||
// }
|
||||
//
|
||||
// impl T for () {<|>
|
||||
//
|
||||
// }
|
||||
// ```
|
||||
// ->
|
||||
// ```
|
||||
// trait T {
|
||||
// Type X;
|
||||
// fn foo(&self);
|
||||
// fn bar(&self) {}
|
||||
// }
|
||||
//
|
||||
// impl T for () {
|
||||
// fn foo(&self) { unimplemented!() }
|
||||
//
|
||||
// }
|
||||
// ```
|
||||
pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
|
||||
add_missing_impl_members_inner(
|
||||
ctx,
|
||||
@ -23,6 +47,36 @@ pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Opti
|
||||
)
|
||||
}
|
||||
|
||||
// Assist: add_impl_default_members
|
||||
// Adds scaffold for overriding default impl members
|
||||
// ```
|
||||
// trait T {
|
||||
// Type X;
|
||||
// fn foo(&self);
|
||||
// fn bar(&self) {}
|
||||
// }
|
||||
//
|
||||
// impl T for () {
|
||||
// Type X = ();
|
||||
// fn foo(&self) {}<|>
|
||||
//
|
||||
// }
|
||||
// ```
|
||||
// ->
|
||||
// ```
|
||||
// trait T {
|
||||
// Type X;
|
||||
// fn foo(&self);
|
||||
// fn bar(&self) {}
|
||||
// }
|
||||
//
|
||||
// impl T for () {
|
||||
// Type X = ();
|
||||
// fn foo(&self) {}
|
||||
// fn bar(&self) {}
|
||||
//
|
||||
// }
|
||||
// ```
|
||||
pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
|
||||
add_missing_impl_members_inner(
|
||||
ctx,
|
||||
|
@ -1,18 +1,26 @@
|
||||
//! This contains the functions associated with the demorgan assist.
|
||||
//! This assist transforms boolean expressions of the form `!a || !b` into
|
||||
//! `!(a && b)`.
|
||||
use hir::db::HirDatabase;
|
||||
use ra_syntax::ast::{self, AstNode};
|
||||
use ra_syntax::SyntaxNode;
|
||||
|
||||
use crate::{Assist, AssistCtx, AssistId};
|
||||
|
||||
/// Assist for applying demorgan's law
|
||||
///
|
||||
/// This transforms expressions of the form `!l || !r` into `!(l && r)`.
|
||||
/// This also works with `&&`. This assist can only be applied with the cursor
|
||||
/// on either `||` or `&&`, with both operands being a negation of some kind.
|
||||
/// This means something of the form `!x` or `x != y`.
|
||||
// Assist: apply_demorgan
|
||||
// Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
|
||||
// This transforms expressions of the form `!l || !r` into `!(l && r)`.
|
||||
// This also works with `&&`. This assist can only be applied with the cursor
|
||||
// on either `||` or `&&`, with both operands being a negation of some kind.
|
||||
// This means something of the form `!x` or `x != y`.
|
||||
// ```
|
||||
// fn main() {
|
||||
// if x != 4 ||<|> !y {}
|
||||
// }
|
||||
// ```
|
||||
// ->
|
||||
// ```
|
||||
// fn main() {
|
||||
// if !(x == 4 && y) {}
|
||||
// }
|
||||
// ```
|
||||
pub(crate) fn apply_demorgan(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
|
||||
let expr = ctx.node_at_offset::<ast::BinExpr>()?;
|
||||
let op = expr.op_kind()?;
|
||||
|
@ -15,8 +15,10 @@ fn check(assist_id: &str, before: &str, after: &str) {
|
||||
let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
|
||||
let frange = FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
|
||||
|
||||
let (_assist_id, action) =
|
||||
crate::assists(&db, frange).into_iter().find(|(id, _)| id.id.0 == assist_id).unwrap();
|
||||
let (_assist_id, action) = crate::assists(&db, frange)
|
||||
.into_iter()
|
||||
.find(|(id, _)| id.id.0 == assist_id)
|
||||
.unwrap_or_else(|| panic!("Assist {:?} is not applicable", assist_id));
|
||||
|
||||
let actual = action.edit.apply(&before);
|
||||
assert_eq_text!(after, &actual);
|
||||
|
@ -2,6 +2,145 @@
|
||||
|
||||
use super::check;
|
||||
|
||||
#[test]
|
||||
fn doctest_add_derive() {
|
||||
check(
|
||||
"add_derive",
|
||||
r#####"
|
||||
struct Point {
|
||||
x: u32,
|
||||
y: u32,<|>
|
||||
}
|
||||
"#####,
|
||||
r#####"
|
||||
#[derive()]
|
||||
struct Point {
|
||||
x: u32,
|
||||
y: u32,
|
||||
}
|
||||
"#####,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_add_explicit_type() {
|
||||
check(
|
||||
"add_explicit_type",
|
||||
r#####"
|
||||
fn main() {
|
||||
let x<|> = 92;
|
||||
}
|
||||
"#####,
|
||||
r#####"
|
||||
fn main() {
|
||||
let x: i32 = 92;
|
||||
}
|
||||
"#####,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_add_impl() {
|
||||
check(
|
||||
"add_impl",
|
||||
r#####"
|
||||
struct Ctx<T: Clone> {
|
||||
data: T,<|>
|
||||
}
|
||||
"#####,
|
||||
r#####"
|
||||
struct Ctx<T: Clone> {
|
||||
data: T,
|
||||
}
|
||||
|
||||
impl<T: Clone> Ctx<T> {
|
||||
|
||||
}
|
||||
"#####,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_add_impl_default_members() {
|
||||
check(
|
||||
"add_impl_default_members",
|
||||
r#####"
|
||||
trait T {
|
||||
Type X;
|
||||
fn foo(&self);
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
impl T for () {
|
||||
Type X = ();
|
||||
fn foo(&self) {}<|>
|
||||
|
||||
}
|
||||
"#####,
|
||||
r#####"
|
||||
trait T {
|
||||
Type X;
|
||||
fn foo(&self);
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
impl T for () {
|
||||
Type X = ();
|
||||
fn foo(&self) {}
|
||||
fn bar(&self) {}
|
||||
|
||||
}
|
||||
"#####,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_add_impl_missing_members() {
|
||||
check(
|
||||
"add_impl_missing_members",
|
||||
r#####"
|
||||
trait T {
|
||||
Type X;
|
||||
fn foo(&self);
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
impl T for () {<|>
|
||||
|
||||
}
|
||||
"#####,
|
||||
r#####"
|
||||
trait T {
|
||||
Type X;
|
||||
fn foo(&self);
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
impl T for () {
|
||||
fn foo(&self) { unimplemented!() }
|
||||
|
||||
}
|
||||
"#####,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_apply_demorgan() {
|
||||
check(
|
||||
"apply_demorgan",
|
||||
r#####"
|
||||
fn main() {
|
||||
if x != 4 ||<|> !y {}
|
||||
}
|
||||
"#####,
|
||||
r#####"
|
||||
fn main() {
|
||||
if !(x == 4 && y) {}
|
||||
}
|
||||
"#####,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_convert_to_guarded_return() {
|
||||
check(
|
||||
|
@ -1,5 +1,142 @@
|
||||
# Assists
|
||||
|
||||
## `add_derive`
|
||||
|
||||
Adds a new `#[derive()]` clause to a struct or enum.
|
||||
|
||||
```rust
|
||||
// BEFORE
|
||||
struct Point {
|
||||
x: u32,
|
||||
y: u32,<|>
|
||||
}
|
||||
|
||||
// AFTER
|
||||
#[derive()]
|
||||
struct Point {
|
||||
x: u32,
|
||||
y: u32,
|
||||
}
|
||||
```
|
||||
|
||||
## `add_explicit_type`
|
||||
|
||||
Specify type for a let binding
|
||||
|
||||
```rust
|
||||
// BEFORE
|
||||
fn main() {
|
||||
let x<|> = 92;
|
||||
}
|
||||
|
||||
// AFTER
|
||||
fn main() {
|
||||
let x: i32 = 92;
|
||||
}
|
||||
```
|
||||
|
||||
## `add_impl`
|
||||
|
||||
Adds a new inherent impl for a type
|
||||
|
||||
```rust
|
||||
// BEFORE
|
||||
struct Ctx<T: Clone> {
|
||||
data: T,<|>
|
||||
}
|
||||
|
||||
// AFTER
|
||||
struct Ctx<T: Clone> {
|
||||
data: T,
|
||||
}
|
||||
|
||||
impl<T: Clone> Ctx<T> {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## `add_impl_default_members`
|
||||
|
||||
Adds scaffold for overriding default impl members
|
||||
|
||||
```rust
|
||||
// BEFORE
|
||||
trait T {
|
||||
Type X;
|
||||
fn foo(&self);
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
impl T for () {
|
||||
Type X = ();
|
||||
fn foo(&self) {}<|>
|
||||
|
||||
}
|
||||
|
||||
// AFTER
|
||||
trait T {
|
||||
Type X;
|
||||
fn foo(&self);
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
impl T for () {
|
||||
Type X = ();
|
||||
fn foo(&self) {}
|
||||
fn bar(&self) {}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## `add_impl_missing_members`
|
||||
|
||||
Adds scaffold for required impl members
|
||||
|
||||
```rust
|
||||
// BEFORE
|
||||
trait T {
|
||||
Type X;
|
||||
fn foo(&self);
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
impl T for () {<|>
|
||||
|
||||
}
|
||||
|
||||
// AFTER
|
||||
trait T {
|
||||
Type X;
|
||||
fn foo(&self);
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
impl T for () {
|
||||
fn foo(&self) { unimplemented!() }
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## `apply_demorgan`
|
||||
|
||||
Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
|
||||
This transforms expressions of the form `!l || !r` into `!(l && r)`.
|
||||
This also works with `&&`. This assist can only be applied with the cursor
|
||||
on either `||` or `&&`, with both operands being a negation of some kind.
|
||||
This means something of the form `!x` or `x != y`.
|
||||
|
||||
```rust
|
||||
// BEFORE
|
||||
fn main() {
|
||||
if x != 4 ||<|> !y {}
|
||||
}
|
||||
|
||||
// AFTER
|
||||
fn main() {
|
||||
if !(x == 4 && y) {}
|
||||
}
|
||||
```
|
||||
|
||||
## `convert_to_guarded_return`
|
||||
|
||||
Replace a large conditional with a guarded return.
|
||||
|
@ -104,84 +104,6 @@ the VS Code side to be able to position cursor. `<|>` signifies cursor
|
||||
|
||||
See [assists.md](./assists.md)
|
||||
|
||||
- Add `#[derive]`
|
||||
|
||||
```rust
|
||||
// before:
|
||||
struct Foo {
|
||||
<|>x: i32
|
||||
}
|
||||
// after:
|
||||
#[derive(<|>)]
|
||||
struct Foo {
|
||||
x: i32
|
||||
}
|
||||
```
|
||||
|
||||
- Add `impl`
|
||||
|
||||
```rust
|
||||
// before:
|
||||
struct Foo<'a, T: Debug> {
|
||||
<|>t: T
|
||||
}
|
||||
// after:
|
||||
struct Foo<'a, T: Debug> {
|
||||
t: T
|
||||
}
|
||||
|
||||
impl<'a, T: Debug> Foo<'a, T> {
|
||||
<|>
|
||||
}
|
||||
```
|
||||
|
||||
- Add missing `impl` members
|
||||
|
||||
```rust
|
||||
// before:
|
||||
trait Foo {
|
||||
fn foo(&self);
|
||||
fn bar(&self);
|
||||
fn baz(&self);
|
||||
}
|
||||
|
||||
struct S;
|
||||
|
||||
impl Foo for S {
|
||||
fn bar(&self) {}
|
||||
<|>
|
||||
}
|
||||
|
||||
// after:
|
||||
trait Foo {
|
||||
fn foo(&self);
|
||||
fn bar(&self);
|
||||
fn baz(&self);
|
||||
}
|
||||
|
||||
struct S;
|
||||
|
||||
impl Foo for S {
|
||||
fn bar(&self) {}
|
||||
fn foo(&self) { unimplemented!() }
|
||||
fn baz(&self) { unimplemented!() }<|>
|
||||
}
|
||||
```
|
||||
|
||||
- Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws)
|
||||
|
||||
```rust
|
||||
// before:
|
||||
fn example(x: bool) -> bool {
|
||||
!x || !x
|
||||
}
|
||||
|
||||
// after:
|
||||
fn example(x: bool) -> bool {
|
||||
!(x && x)
|
||||
}
|
||||
```
|
||||
|
||||
- Import path
|
||||
|
||||
```rust
|
||||
@ -391,19 +313,6 @@ fn foo() {
|
||||
}
|
||||
```
|
||||
|
||||
- Add explicit type
|
||||
|
||||
```rust
|
||||
// before:
|
||||
fn foo() {
|
||||
let t<|> = (&2, Some(1));
|
||||
}
|
||||
// after:
|
||||
fn foo() {
|
||||
let t<|>: (&i32, Option<i32>) = (&2, Some(1));
|
||||
}
|
||||
```
|
||||
|
||||
- Move guard expression to match arm body
|
||||
```rust
|
||||
// before:
|
||||
|
@ -74,6 +74,14 @@ fn reformat(text: impl std::fmt::Display) -> Result<String> {
|
||||
}
|
||||
|
||||
fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> {
|
||||
do_extract_comment_blocks(text, false)
|
||||
}
|
||||
|
||||
fn extract_comment_blocks_with_empty_lines(text: &str) -> Vec<Vec<String>> {
|
||||
do_extract_comment_blocks(text, true)
|
||||
}
|
||||
|
||||
fn do_extract_comment_blocks(text: &str, allow_blocks_with_empty_lins: bool) -> Vec<Vec<String>> {
|
||||
let mut res = Vec::new();
|
||||
|
||||
let prefix = "// ";
|
||||
@ -81,6 +89,11 @@ fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> {
|
||||
|
||||
let mut block = vec![];
|
||||
for line in lines {
|
||||
if line == "//" && allow_blocks_with_empty_lins {
|
||||
block.push(String::new());
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_comment = line.starts_with(prefix);
|
||||
if is_comment {
|
||||
block.push(line[prefix.len()..].to_string());
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::{fs, path::Path};
|
||||
|
||||
use crate::{
|
||||
codegen::{self, extract_comment_blocks, Mode},
|
||||
codegen::{self, extract_comment_blocks_with_empty_lines, Mode},
|
||||
project_root, Result,
|
||||
};
|
||||
|
||||
@ -34,7 +34,7 @@ fn collect_assists() -> Result<Vec<Assist>> {
|
||||
|
||||
fn collect_file(acc: &mut Vec<Assist>, path: &Path) -> Result<()> {
|
||||
let text = fs::read_to_string(path)?;
|
||||
let comment_blocks = extract_comment_blocks(&text);
|
||||
let comment_blocks = extract_comment_blocks_with_empty_lines(&text);
|
||||
|
||||
for block in comment_blocks {
|
||||
// FIXME: doesn't support blank lines yet, need to tweak
|
||||
@ -45,7 +45,11 @@ fn collect_file(acc: &mut Vec<Assist>, path: &Path) -> Result<()> {
|
||||
continue;
|
||||
}
|
||||
let id = first_line["Assist: ".len()..].to_string();
|
||||
assert!(id.chars().all(|it| it.is_ascii_lowercase() || it == '_'));
|
||||
assert!(
|
||||
id.chars().all(|it| it.is_ascii_lowercase() || it == '_'),
|
||||
"invalid assist id: {:?}",
|
||||
id
|
||||
);
|
||||
|
||||
let doc = take_until(lines.by_ref(), "```");
|
||||
let before = take_until(lines.by_ref(), "```");
|
||||
|
Loading…
Reference in New Issue
Block a user