about summary refs log tree commit diff
diff options
context:
space:
mode:
authoralibektas <bektasali@protonmail.com>2023-04-17 00:41:08 +0300
committerAli Bektas <bektasali@protonmail.com>2023-05-23 03:12:57 +0200
commit51ec2ced69901f34b3097a6af12b7dd102ed504c (patch)
tree48d898e0dfd3061bb10250e4330f05b5a5c0ccd0
parent2120c913c28896ed8e6247906f8884939c268683 (diff)
downloadrust-51ec2ced69901f34b3097a6af12b7dd102ed504c.tar.gz
rust-51ec2ced69901f34b3097a6af12b7dd102ed504c.zip
Improve ast::make
Add `ty_alias` and make `impl_trait` , `fn` and `impl_` have more coverage.
-rw-r--r--crates/ide-assists/src/handlers/generate_delegate_methods.rs31
-rw-r--r--crates/ide-assists/src/handlers/generate_function.rs2
-rw-r--r--crates/syntax/src/ast/make.rs127
3 files changed, 126 insertions, 34 deletions
diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index a0813c91154..23e6adcf53a 100644
--- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -116,12 +116,25 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
                 );
                 let ret_type = method_source.ret_type();
                 let is_async = method_source.async_token().is_some();
+                let is_const = method_source.const_token().is_some();
+                let is_unsafe = method_source.unsafe_token().is_some();
                 let tail_expr_finished =
                     if is_async { make::expr_await(tail_expr) } else { tail_expr };
                 let body = make::block_expr([], Some(tail_expr_finished));
-                let f = make::fn_(vis, name, type_params, None, params, body, ret_type, is_async)
-                    .indent(ast::edit::IndentLevel(1))
-                    .clone_for_update();
+                let f = make::fn_(
+                    vis,
+                    name,
+                    type_params,
+                    None,
+                    params,
+                    body,
+                    ret_type,
+                    is_async,
+                    is_const,
+                    is_unsafe,
+                )
+                .indent(ast::edit::IndentLevel(1))
+                .clone_for_update();
 
                 let cursor = Cursor::Before(f.syntax());
 
@@ -153,8 +166,16 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
                         let name = &strukt_name.to_string();
                         let params = strukt.generic_param_list();
                         let ty_params = params.clone();
-                        let impl_def = make::impl_(make::ext::ident_path(name), params, ty_params)
-                            .clone_for_update();
+                        let where_clause = strukt.where_clause();
+
+                        let impl_def = make::impl_(
+                            ty_params,
+                            None,
+                            make::ty_path(make::ext::ident_path(name)),
+                            where_clause,
+                            None,
+                        )
+                        .clone_for_update();
                         let assoc_items = impl_def.get_or_create_assoc_item_list();
                         assoc_items.add_item(f.clone().into());
 
diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs
index 739b466b311..68b61fc03ff 100644
--- a/crates/ide-assists/src/handlers/generate_function.rs
+++ b/crates/ide-assists/src/handlers/generate_function.rs
@@ -378,6 +378,8 @@ impl FunctionBuilder {
             fn_body,
             self.ret_type,
             self.is_async,
+            false, // FIXME : const and unsafe are not handled yet.
+            false,
         );
         let leading_ws;
         let trailing_ws;
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index cc0d7f4b48e..3472a424587 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -158,13 +158,6 @@ fn ty_from_text(text: &str) -> ast::Type {
     ast_from_text(&format!("type _T = {text};"))
 }
 
-/// Related goto [link](https://doc.rust-lang.org/reference/items/type-aliases.html)
-/// Type Alias syntax is
-/// ```
-/// TypeAlias :
-/// type IDENTIFIER GenericParams? ( : TypeParamBounds )? WhereClause? ( = Type WhereClause?)? ;
-/// ```
-/// FIXME : ident should be of type ast::Ident
 pub fn ty_alias(
     ident: &str,
     generic_param_list: Option<ast::GenericParamList>,
@@ -173,7 +166,7 @@ pub fn ty_alias(
     assignment: Option<(ast::Type, Option<ast::WhereClause>)>,
 ) -> ast::TypeAlias {
     let mut s = String::new();
-    s.push_str(&format!("type {}", ident));
+    s.push_str(&format!("type {} ", ident));
 
     if let Some(list) = generic_param_list {
         s.push_str(&list.to_string());
@@ -203,33 +196,106 @@ pub fn assoc_item_list() -> ast::AssocItemList {
     ast_from_text("impl C for D {}")
 }
 
-// FIXME: `ty_params` should be `ast::GenericArgList`
+fn merge_gen_params(
+    ps: Option<ast::GenericParamList>,
+    bs: Option<ast::GenericParamList>,
+) -> Option<ast::GenericParamList> {
+    match (ps, bs) {
+        (None, None) => None,
+        (None, Some(bs)) => Some(bs),
+        (Some(ps), None) => Some(ps),
+        (Some(ps), Some(bs)) => {
+            for b in bs.generic_params() {
+                ps.add_generic_param(b);
+            }
+            Some(ps)
+        }
+    }
+}
+
 pub fn impl_(
-    ty: ast::Path,
-    params: Option<ast::GenericParamList>,
-    ty_params: Option<ast::GenericParamList>,
+    generic_params: Option<ast::GenericParamList>,
+    generic_args: Option<ast::GenericParamList>,
+    path_type: ast::Type,
+    where_clause: Option<ast::WhereClause>,
+    body: Option<Vec<either::Either<ast::Attr, ast::AssocItem>>>,
 ) -> ast::Impl {
-    let params = match params {
-        Some(params) => params.to_string(),
-        None => String::new(),
+    let (gen_params, tr_gen_args) = match (generic_params, generic_args) {
+        (None, None) => (String::new(), String::new()),
+        (None, Some(args)) => (String::new(), args.to_generic_args().to_string()),
+        (Some(params), None) => (params.to_string(), params.to_generic_args().to_string()),
+        (Some(params), Some(args)) => match merge_gen_params(Some(params.clone()), Some(args)) {
+            Some(merged) => (params.to_string(), merged.to_generic_args().to_string()),
+            None => (params.to_string(), String::new()),
+        },
     };
-    let ty_params = match ty_params {
-        Some(params) => params.to_string(),
+
+    let where_clause = match where_clause {
+        Some(pr) => pr.to_string(),
+        None => " ".to_string(),
+    };
+
+    let body = match body {
+        Some(bd) => bd.iter().map(|elem| elem.to_string()).join(""),
         None => String::new(),
     };
-    ast_from_text(&format!("impl{params} {ty}{ty_params} {{}}"))
+
+    ast_from_text(&format!("impl{gen_params} {path_type}{tr_gen_args}{where_clause}{{{}}}", body))
 }
 
+// FIXME : We must make *_gen_args' type ast::GenericArgList but in order to do so we must implement in `edit_in_place.rs`
+// `add_generic_arg()` just like `add_generic_param()`
+// is implemented for `ast::GenericParamList`
 pub fn impl_trait(
-    trait_: ast::Path,
-    ty: ast::Path,
-    ty_params: Option<ast::GenericParamList>,
+    is_unsafe: bool,
+    trait_gen_params: Option<ast::GenericParamList>,
+    trait_gen_args: Option<ast::GenericParamList>,
+    type_gen_params: Option<ast::GenericParamList>,
+    type_gen_args: Option<ast::GenericParamList>,
+    is_negative: bool,
+    path_type: ast::Type,
+    ty: ast::Type,
+    trait_where_clause: Option<ast::WhereClause>,
+    ty_where_clause: Option<ast::WhereClause>,
+    body: Option<Vec<either::Either<ast::Attr, ast::AssocItem>>>,
 ) -> ast::Impl {
-    // TODO : If this function is now correct we can also change `impl_` accordingly`
-    let ty_params_str = ty_params.as_ref().map_or_else(String::new, |params| params.to_string());
-    let ty_genargs_str =
-        ty_params.map_or_else(String::new, |params| params.to_generic_args().to_string());
-    ast_from_text(&format!("impl{ty_params_str} {trait_} for {ty}{ty_genargs_str} {{}}"))
+    let is_unsafe = if is_unsafe { "unsafe " } else { "" };
+    let ty_gen_args = match merge_gen_params(type_gen_params.clone(), type_gen_args) {
+        Some(pars) => pars.to_generic_args().to_string(),
+        None => String::new(),
+    };
+
+    let tr_gen_args = match merge_gen_params(trait_gen_params.clone(), trait_gen_args) {
+        Some(pars) => pars.to_generic_args().to_string(),
+        None => String::new(),
+    };
+
+    let gen_params = match merge_gen_params(trait_gen_params, type_gen_params) {
+        Some(pars) => pars.to_string(),
+        None => String::new(),
+    };
+
+    let is_negative = if is_negative { "! " } else { "" };
+
+    let where_clause = match (ty_where_clause, trait_where_clause) {
+        (None, None) => " ".to_string(),
+        (None, Some(tr)) => format!("\n{}\n", tr).to_string(),
+        (Some(ty), None) => format!("\n{}\n", ty).to_string(),
+        (Some(ty), Some(tr)) => {
+            let updated = ty.clone_for_update();
+            tr.predicates().for_each(|p| {
+                ty.add_predicate(p);
+            });
+            format!("\n{}\n", updated).to_string()
+        }
+    };
+
+    let body = match body {
+        Some(bd) => bd.iter().map(|elem| elem.to_string()).join(""),
+        None => String::new(),
+    };
+
+    ast_from_text(&format!("{is_unsafe}impl{gen_params} {is_negative}{path_type}{tr_gen_args} for {ty}{ty_gen_args}{where_clause}{{{}}}" , body))
 }
 
 pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
@@ -871,6 +937,8 @@ pub fn fn_(
     body: ast::BlockExpr,
     ret_type: Option<ast::RetType>,
     is_async: bool,
+    is_const: bool,
+    is_unsafe: bool,
 ) -> ast::Fn {
     let type_params = match type_params {
         Some(type_params) => format!("{type_params}"),
@@ -890,12 +958,13 @@ pub fn fn_(
     };
 
     let async_literal = if is_async { "async " } else { "" };
+    let const_literal = if is_const { "const " } else { "" };
+    let unsafe_literal = if is_unsafe { "unsafe " } else { "" };
 
     ast_from_text(&format!(
-        "{visibility}{async_literal}fn {fn_name}{type_params}{params} {ret_type}{where_clause}{body}",
+        "{visibility}{async_literal}{const_literal}{unsafe_literal}fn {fn_name}{type_params}{params} {ret_type}{where_clause}{body}",
     ))
 }
-
 pub fn struct_(
     visibility: Option<ast::Visibility>,
     strukt_name: ast::Name,
@@ -945,7 +1014,7 @@ pub mod tokens {
 
     pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| {
         SourceFile::parse(
-            "const C: <()>::Item = (1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p)\n;\n\n",
+            "const C: <()>::Item = (1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p)\n;\n\n",
         )
     });