3 use ide_db::{helpers::FamousDefs, RootDatabase};
5 ast::{self, NameOwner},
10 assist_context::{AssistBuilder, AssistContext, Assists},
11 utils::generate_trait_impl_text,
15 // Assist: generate_deref
17 // Generate `Deref` impl using the given struct field.
32 // impl std::ops::Deref for B {
35 // fn deref(&self) -> &Self::Target {
40 pub(crate) fn generate_deref(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
41 generate_record_deref(acc, ctx).or_else(|| generate_tuple_deref(acc, ctx))
44 fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
45 let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
46 let field = ctx.find_node_at_offset::<ast::RecordField>()?;
48 if existing_deref_impl(&ctx.sema, &strukt).is_some() {
49 cov_mark::hit!(test_add_record_deref_impl_already_exists);
53 let field_type = field.ty()?;
54 let field_name = field.name()?;
55 let target = field.syntax().text_range();
57 AssistId("generate_deref", AssistKind::Generate),
58 format!("Generate `Deref` impl using `{}`", field_name),
60 |edit| generate_edit(edit, strukt, field_type.syntax(), field_name.syntax()),
64 fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
65 let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
66 let field = ctx.find_node_at_offset::<ast::TupleField>()?;
67 let field_list = ctx.find_node_at_offset::<ast::TupleFieldList>()?;
68 let field_list_index =
69 field_list.syntax().children().into_iter().position(|s| &s == field.syntax())?;
71 if existing_deref_impl(&ctx.sema, &strukt).is_some() {
72 cov_mark::hit!(test_add_field_deref_impl_already_exists);
76 let field_type = field.ty()?;
77 let target = field.syntax().text_range();
79 AssistId("generate_deref", AssistKind::Generate),
80 format!("Generate `Deref` impl using `{}`", field.syntax()),
82 |edit| generate_edit(edit, strukt, field_type.syntax(), field_list_index),
87 edit: &mut AssistBuilder,
89 field_type_syntax: &SyntaxNode,
90 field_name: impl Display,
92 let start_offset = strukt.syntax().text_range().end();
93 let impl_code = format!(
94 r#" type Target = {0};
96 fn deref(&self) -> &Self::Target {{
99 field_type_syntax, field_name
101 let strukt_adt = ast::Adt::Struct(strukt);
102 let deref_impl = generate_trait_impl_text(&strukt_adt, "std::ops::Deref", &impl_code);
103 edit.insert(start_offset, deref_impl);
106 fn existing_deref_impl(
107 sema: &'_ hir::Semantics<'_, RootDatabase>,
108 strukt: &ast::Struct,
110 let strukt = sema.to_def(strukt)?;
111 let krate = strukt.module(sema.db).krate();
113 let deref_trait = FamousDefs(sema, Some(krate)).core_ops_Deref()?;
114 let strukt_type = strukt.ty(sema.db);
116 if strukt_type.impls_trait(sema.db, deref_trait, &[]) {
125 use crate::tests::{check_assist, check_assist_not_applicable};
130 fn test_generate_record_deref() {
134 struct B { $0a: A }"#,
138 impl std::ops::Deref for B {
141 fn deref(&self) -> &Self::Target {
149 fn test_generate_field_deref_idx_0() {
157 impl std::ops::Deref for B {
160 fn deref(&self) -> &Self::Target {
167 fn test_generate_field_deref_idx_1() {
171 struct B(u8, $0A);"#,
175 impl std::ops::Deref for B {
178 fn deref(&self) -> &Self::Target {
186 fn test_generate_record_deref_not_applicable_if_already_impl() {
187 cov_mark::check!(test_add_record_deref_impl_already_exists);
188 check_assist_not_applicable(
195 impl core::ops::Deref for B {
198 fn deref(&self) -> &Self::Target {
206 fn test_generate_field_deref_not_applicable_if_already_impl() {
207 cov_mark::check!(test_add_field_deref_impl_already_exists);
208 check_assist_not_applicable(
215 impl core::ops::Deref for B {
218 fn deref(&self) -> &Self::Target {