about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-02-05 17:18:02 +0000
committerGitHub <noreply@github.com>2021-02-05 17:18:02 +0000
commit80ab753d7e0bf59b81df317d6ddda43cb919ec83 (patch)
tree934a7ae2d8b549cd9d5d82a137156c0a71220973
parent941f9157f5561868c4683d54fdf98378383f64b8 (diff)
parent2cf161266941eac300ae66a633ead26f5109ea16 (diff)
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>
-rw-r--r--crates/assists/src/handlers/generate_enum_match_method.rs20
-rw-r--r--crates/assists/src/handlers/generate_new.rs21
-rw-r--r--crates/assists/src/utils.rs18
3 files changed, 30 insertions, 29 deletions
diff --git a/crates/assists/src/handlers/generate_enum_match_method.rs b/crates/assists/src/handlers/generate_enum_match_method.rs
index ee89d420854..4cf66b5d5c1 100644
--- a/crates/assists/src/handlers/generate_enum_match_method.rs
+++ b/crates/assists/src/handlers/generate_enum_match_method.rs
@@ -1,9 +1,12 @@
 use stdx::{format_to, to_lower_snake_case};
+use syntax::ast::VisibilityOwner;
 use syntax::ast::{self, AstNode, NameOwner};
-use syntax::{ast::VisibilityOwner, T};
 use test_utils::mark;
 
-use crate::{utils::find_struct_impl, AssistContext, AssistId, AssistKind, Assists};
+use crate::{
+    utils::{find_impl_block, find_struct_impl},
+    AssistContext, AssistId, AssistKind, Assists,
+};
 
 // Assist: generate_enum_match_method
 //
@@ -63,7 +66,6 @@ pub(crate) fn generate_enum_match_method(acc: &mut Assists, ctx: &AssistContext)
             }
 
             let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
-
             format_to!(
                 buf,
                 "    /// Returns `true` if the {} is [`{}`].
@@ -78,17 +80,7 @@ pub(crate) fn generate_enum_match_method(acc: &mut Assists, ctx: &AssistContext)
             );
 
             let start_offset = impl_def
-                .and_then(|impl_def| {
-                    buf.push('\n');
-                    let start = impl_def
-                        .syntax()
-                        .descendants_with_tokens()
-                        .find(|t| t.kind() == T!['{'])?
-                        .text_range()
-                        .end();
-
-                    Some(start)
-                })
+                .and_then(|impl_def| find_impl_block(impl_def, &mut buf))
                 .unwrap_or_else(|| {
                     buf = generate_impl_text(&parent_enum, &buf);
                     parent_enum.syntax().text_range().end()
diff --git a/crates/assists/src/handlers/generate_new.rs b/crates/assists/src/handlers/generate_new.rs
index 84832273f49..307f2e228c9 100644
--- a/crates/assists/src/handlers/generate_new.rs
+++ b/crates/assists/src/handlers/generate_new.rs
@@ -2,10 +2,13 @@ use itertools::Itertools;
 use stdx::format_to;
 use syntax::{
     ast::{self, AstNode, GenericParamsOwner, NameOwner, StructKind, VisibilityOwner},
-    SmolStr, T,
+    SmolStr,
 };
 
-use crate::{utils::find_struct_impl, AssistContext, AssistId, AssistKind, Assists};
+use crate::{
+    utils::{find_impl_block, find_struct_impl},
+    AssistContext, AssistId, AssistKind, Assists,
+};
 
 // Assist: generate_new
 //
@@ -58,17 +61,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
         format_to!(buf, "    {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields);
 
         let start_offset = impl_def
-            .and_then(|impl_def| {
-                buf.push('\n');
-                let start = impl_def
-                    .syntax()
-                    .descendants_with_tokens()
-                    .find(|t| t.kind() == T!['{'])?
-                    .text_range()
-                    .end();
-
-                Some(start)
-            })
+            .and_then(|impl_def| find_impl_block(impl_def, &mut buf))
             .unwrap_or_else(|| {
                 buf = generate_impl_text(&strukt, &buf);
                 strukt.syntax().text_range().end()
@@ -93,7 +86,7 @@ fn generate_impl_text(strukt: &ast::Struct, code: &str) -> String {
     if let Some(type_params) = &type_params {
         format_to!(buf, "{}", type_params.syntax());
     }
-    buf.push_str(" ");
+    buf.push(' ');
     buf.push_str(strukt.name().unwrap().text());
     if let Some(type_params) = type_params {
         let lifetime_params = type_params
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index 3842558d8da..8045aac40cd 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -274,10 +274,11 @@ pub(crate) fn does_pat_match_variant(pat: &ast::Pat, var: &ast::Pat) -> bool {
 // Uses a syntax-driven approach to find any impl blocks for the struct that
 // exist within the module/file
 //
-// Returns `None` if we've found an existing `new` fn
+// Returns `None` if we've found an existing fn
 //
 // FIXME: change the new fn checking to a more semantic approach when that's more
 // viable (e.g. we process proc macros, etc)
+// FIXME: this partially overlaps with `find_impl_block`
 pub(crate) fn find_struct_impl(
     ctx: &AssistContext,
     strukt: &ast::AdtDef,
@@ -338,3 +339,18 @@ fn has_fn(imp: &ast::Impl, rhs_name: &str) -> bool {
 
     false
 }
+
+/// Find the start of the `impl` block for the given `ast::Impl`.
+//
+// FIXME: add a way to find the end of the `impl` block.
+// FIXME: this partially overlaps with `find_struct_impl`
+pub(crate) fn find_impl_block(impl_def: ast::Impl, buf: &mut String) -> Option<TextSize> {
+    buf.push('\n');
+    let start = impl_def
+        .syntax()
+        .descendants_with_tokens()
+        .find(|t| t.kind() == T!['{'])?
+        .text_range()
+        .end();
+    Some(start)
+}