about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTheDoctor314 <64731940+TheDoctor314@users.noreply.github.com>2021-11-11 14:16:59 +0530
committerTheDoctor314 <64731940+TheDoctor314@users.noreply.github.com>2021-11-11 14:16:59 +0530
commit55a4813151a8f36dcdb520c45a461fe5dfbed499 (patch)
treefea8500d8d163cb32e7f10688d246e8a05dde099
parente0e8d877c0f4908e877b8ad7ea82acc8cf90be9b (diff)
downloadrust-55a4813151a8f36dcdb520c45a461fe5dfbed499.tar.gz
rust-55a4813151a8f36dcdb520c45a461fe5dfbed499.zip
Fix `impl_trait` function to emit correct ast
`impl_trait` code copied from `generate_impl_text_inner` to properly
handle the bounds for the generic parameters.
-rw-r--r--crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs9
-rw-r--r--crates/syntax/src/ast/make.rs72
2 files changed, 67 insertions, 14 deletions
diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
index 1f28ecc755f..060bb17c6d2 100644
--- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -3,7 +3,7 @@ use ide_db::helpers::{import_assets::NameToImport, mod_path_to_ast};
 use ide_db::items_locator;
 use itertools::Itertools;
 use syntax::{
-    ast::{self, make, AstNode, HasGenericParams, HasName},
+    ast::{self, make, AstNode, HasName},
     SyntaxKind::{IDENT, WHITESPACE},
 };
 
@@ -160,11 +160,8 @@ fn impl_def_from_trait(
     if trait_items.is_empty() {
         return None;
     }
-    let impl_def = make::impl_trait(
-        trait_path.clone(),
-        make::ext::ident_path(&annotated_name.text()),
-        adt.generic_param_list(),
-    );
+    let impl_def = make::impl_trait(&trait_path, &adt, "");
+
     let (impl_def, first_assoc_item) =
         add_trait_assoc_items_to_impl(sema, trait_items, trait_, impl_def, target_scope);
 
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index e1938307cf3..fec7c5cfe80 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -10,9 +10,13 @@
 //! `parse(format!())` we use internally is an implementation detail -- long
 //! term, it will be replaced with direct tree manipulation.
 use itertools::Itertools;
+use smol_str::SmolStr;
 use stdx::{format_to, never};
 
-use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxToken};
+use crate::{
+    ast::{self, HasAttrs, HasGenericParams, HasName, HasTypeBounds},
+    AstNode, SourceFile, SyntaxKind, SyntaxToken,
+};
 
 /// While the parent module defines basic atomic "constructors", the `ext`
 /// module defines shortcuts for common things.
@@ -149,13 +153,65 @@ pub fn impl_(
     ast_from_text(&format!("impl{} {}{} {{}}", params, ty, ty_params))
 }
 
-pub fn impl_trait(
-    trait_: ast::Path,
-    ty: ast::Path,
-    ty_params: Option<ast::GenericParamList>,
-) -> ast::Impl {
-    let ty_params = ty_params.map_or_else(String::new, |params| params.to_string());
-    ast_from_text(&format!("impl{2} {} for {}{2} {{}}", trait_, ty, ty_params))
+pub fn impl_trait(trait_: &ast::Path, adt: &ast::Adt, code: &str) -> ast::Impl {
+    let generic_params = adt.generic_param_list();
+    let mut buf = String::with_capacity(code.len());
+    buf.push_str("\n\n");
+    adt.attrs()
+        .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false))
+        .for_each(|attr| buf.push_str(format!("{}\n", attr.to_string()).as_str()));
+    buf.push_str("impl");
+    if let Some(generic_params) = &generic_params {
+        let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
+        let type_params = generic_params.type_params().map(|type_param| {
+            let mut buf = String::new();
+            if let Some(it) = type_param.name() {
+                format_to!(buf, "{}", it.syntax());
+            }
+            if let Some(it) = type_param.colon_token() {
+                format_to!(buf, "{} ", it);
+            }
+            if let Some(it) = type_param.type_bound_list() {
+                format_to!(buf, "{}", it.syntax());
+            }
+            buf
+        });
+        let const_params = generic_params.const_params().map(|t| t.syntax().to_string());
+        let generics = lifetimes.chain(type_params).chain(const_params).format(", ");
+        format_to!(buf, "<{}>", generics);
+    }
+    buf.push(' ');
+    let trait_text = trait_.to_string();
+    buf.push_str(&trait_text);
+    buf.push_str(" for ");
+
+    buf.push_str(&adt.name().unwrap().text());
+    if let Some(generic_params) = generic_params {
+        let lifetime_params = generic_params
+            .lifetime_params()
+            .filter_map(|it| it.lifetime())
+            .map(|it| SmolStr::from(it.text()));
+        let type_params = generic_params
+            .type_params()
+            .filter_map(|it| it.name())
+            .map(|it| SmolStr::from(it.text()));
+        let const_params = generic_params
+            .const_params()
+            .filter_map(|it| it.name())
+            .map(|it| SmolStr::from(it.text()));
+        format_to!(buf, "<{}>", lifetime_params.chain(type_params).chain(const_params).format(", "))
+    }
+
+    match adt.where_clause() {
+        Some(where_clause) => {
+            format_to!(buf, "\n{}\n{{\n{}\n}}", where_clause, code);
+        }
+        None => {
+            format_to!(buf, " {{\n{}\n}}", code);
+        }
+    }
+
+    ast_from_text(&buf)
 }
 
 pub(crate) fn generic_arg_list() -> ast::GenericArgList {