Skip to content

Commit aca14c5

Browse files
bors[bot]matklad
andcommitted
Merge #475
475: Show types of fields in completion r=matklad a=matklad ![image](https://user-images.githubusercontent.com/1711539/50910524-0f146200-143f-11e9-84d6-0ba80761cd89.png) r? @flodiebold Co-authored-by: Aleksey Kladov <[email protected]>
2 parents aef93c9 + 56b2138 commit aca14c5

File tree

6 files changed

+99
-59
lines changed

6 files changed

+99
-59
lines changed

crates/ra_hir/src/adt.rs

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@ use ra_db::Cancelable;
44
use ra_syntax::ast::{self, NameOwner, StructFlavor, AstNode};
55

66
use crate::{
7-
DefId, Name, AsName, Struct, Enum, VariantData, StructField, HirDatabase, DefKind,
7+
DefId, Name, AsName, Struct, Enum, HirDatabase, DefKind,
88
type_ref::TypeRef,
99
};
1010

1111
impl Struct {
1212
pub(crate) fn new(def_id: DefId) -> Self {
1313
Struct { def_id }
1414
}
15+
16+
pub(crate) fn variant_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<VariantData>> {
17+
Ok(db.struct_data(self.def_id)?.variant_data.clone())
18+
}
1519
}
1620

1721
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -83,6 +87,51 @@ impl EnumData {
8387
}
8488
}
8589

90+
/// A single field of an enum variant or struct
91+
#[derive(Debug, Clone, PartialEq, Eq)]
92+
pub struct StructField {
93+
pub(crate) name: Name,
94+
pub(crate) type_ref: TypeRef,
95+
}
96+
97+
/// Fields of an enum variant or struct
98+
#[derive(Debug, Clone, PartialEq, Eq)]
99+
pub enum VariantData {
100+
Struct(Vec<StructField>),
101+
Tuple(Vec<StructField>),
102+
Unit,
103+
}
104+
105+
impl VariantData {
106+
pub fn fields(&self) -> &[StructField] {
107+
match self {
108+
VariantData::Struct(fields) | VariantData::Tuple(fields) => fields,
109+
_ => &[],
110+
}
111+
}
112+
113+
pub fn is_struct(&self) -> bool {
114+
match self {
115+
VariantData::Struct(..) => true,
116+
_ => false,
117+
}
118+
}
119+
120+
pub fn is_tuple(&self) -> bool {
121+
match self {
122+
VariantData::Tuple(..) => true,
123+
_ => false,
124+
}
125+
}
126+
127+
pub fn is_unit(&self) -> bool {
128+
match self {
129+
VariantData::Unit => true,
130+
_ => false,
131+
}
132+
}
133+
}
134+
86135
impl VariantData {
87136
fn new(flavor: StructFlavor) -> Self {
88137
match flavor {
@@ -114,7 +163,7 @@ impl VariantData {
114163
pub(crate) fn get_field_type_ref(&self, field_name: &Name) -> Option<&TypeRef> {
115164
self.fields()
116165
.iter()
117-
.find(|f| f.name() == field_name)
118-
.map(|f| f.type_ref())
166+
.find(|f| f.name == *field_name)
167+
.map(|f| &f.type_ref)
119168
}
120169
}

crates/ra_hir/src/code_model_api.rs

Lines changed: 19 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use ra_db::{CrateId, Cancelable, FileId};
55
use ra_syntax::{ast, TreePtr, SyntaxNode};
66

77
use crate::{
8-
Name, DefId, Path, PerNs, ScopesWithSyntaxMapping,
8+
Name, DefId, Path, PerNs, ScopesWithSyntaxMapping, Ty,
99
type_ref::TypeRef,
1010
nameres::ModuleScope,
1111
db::HirDatabase,
1212
expr::BodySyntaxMapping,
1313
ty::InferenceResult,
14+
adt::VariantData,
1415
};
1516

1617
/// hir::Crate describes a single crate. It's the main interface with which
@@ -137,58 +138,18 @@ impl Module {
137138
}
138139
}
139140

140-
/// A single field of an enum variant or struct
141-
#[derive(Debug, Clone, PartialEq, Eq)]
141+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
142142
pub struct StructField {
143-
pub(crate) name: Name,
144-
pub(crate) type_ref: TypeRef,
143+
struct_: Struct,
144+
name: Name,
145145
}
146146

147147
impl StructField {
148148
pub fn name(&self) -> &Name {
149149
&self.name
150150
}
151-
152-
pub fn type_ref(&self) -> &TypeRef {
153-
&self.type_ref
154-
}
155-
}
156-
157-
/// Fields of an enum variant or struct
158-
#[derive(Debug, Clone, PartialEq, Eq)]
159-
pub enum VariantData {
160-
Struct(Vec<StructField>),
161-
Tuple(Vec<StructField>),
162-
Unit,
163-
}
164-
165-
impl VariantData {
166-
pub fn fields(&self) -> &[StructField] {
167-
match self {
168-
VariantData::Struct(fields) | VariantData::Tuple(fields) => fields,
169-
_ => &[],
170-
}
171-
}
172-
173-
pub fn is_struct(&self) -> bool {
174-
match self {
175-
VariantData::Struct(..) => true,
176-
_ => false,
177-
}
178-
}
179-
180-
pub fn is_tuple(&self) -> bool {
181-
match self {
182-
VariantData::Tuple(..) => true,
183-
_ => false,
184-
}
185-
}
186-
187-
pub fn is_unit(&self) -> bool {
188-
match self {
189-
VariantData::Unit => true,
190-
_ => false,
191-
}
151+
pub fn ty(&self, db: &impl HirDatabase) -> Cancelable<Option<Ty>> {
152+
db.type_for_field(self.struct_.def_id, self.name.clone())
192153
}
193154
}
194155

@@ -206,8 +167,18 @@ impl Struct {
206167
Ok(db.struct_data(self.def_id)?.name.clone())
207168
}
208169

209-
pub fn variant_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<VariantData>> {
210-
Ok(db.struct_data(self.def_id)?.variant_data.clone())
170+
pub fn fields(&self, db: &impl HirDatabase) -> Cancelable<Vec<StructField>> {
171+
let res = db
172+
.struct_data(self.def_id)?
173+
.variant_data
174+
.fields()
175+
.iter()
176+
.map(|it| StructField {
177+
struct_: self.clone(),
178+
name: it.name.clone(),
179+
})
180+
.collect();
181+
Ok(res)
211182
}
212183
}
213184

crates/ra_hir/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,6 @@ pub use self::code_model_api::{
5656
Crate, CrateDependency,
5757
Def,
5858
Module, ModuleSource, Problem,
59-
Struct, Enum, VariantData, StructField,
59+
Struct, Enum,
6060
Function, FnSignature,
6161
};

crates/ra_ide_api/src/completion/complete_dot.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
2828
Ty::Adt { def_id, .. } => {
2929
match def_id.resolve(ctx.db)? {
3030
Def::Struct(s) => {
31-
let variant_data = s.variant_data(ctx.db)?;
32-
for field in variant_data.fields() {
31+
for field in s.fields(ctx.db)? {
3332
CompletionItem::new(
3433
CompletionKind::Reference,
3534
field.name().to_string(),
3635
)
3736
.kind(CompletionItemKind::Field)
37+
.set_detail(field.ty(ctx.db)?.map(|ty| ty.to_string()))
3838
.add_to(acc);
3939
}
4040
}
@@ -72,37 +72,37 @@ mod tests {
7272
a.<|>
7373
}
7474
",
75-
r#"the_field"#,
75+
r#"the_field "u32""#,
7676
);
7777
}
7878

7979
#[test]
8080
fn test_struct_field_completion_self() {
8181
check_ref_completion(
8282
r"
83-
struct A { the_field: u32 }
83+
struct A { the_field: (u32,) }
8484
impl A {
8585
fn foo(self) {
8686
self.<|>
8787
}
8888
}
8989
",
90-
r#"the_field"#,
90+
r#"the_field "(u32,)""#,
9191
);
9292
}
9393

9494
#[test]
9595
fn test_struct_field_completion_autoderef() {
9696
check_ref_completion(
9797
r"
98-
struct A { the_field: u32 }
98+
struct A { the_field: (u32, i32) }
9999
impl A {
100100
fn foo(&self) {
101101
self.<|>
102102
}
103103
}
104104
",
105-
r#"the_field"#,
105+
r#"the_field "(u32, i32)""#,
106106
);
107107
}
108108

crates/ra_ide_api/src/completion/completion_item.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub struct CompletionItem {
1111
/// completion.
1212
completion_kind: CompletionKind,
1313
label: String,
14+
detail: Option<String>,
1415
lookup: Option<String>,
1516
snippet: Option<String>,
1617
kind: Option<CompletionItemKind>,
@@ -51,6 +52,7 @@ impl CompletionItem {
5152
Builder {
5253
completion_kind,
5354
label,
55+
detail: None,
5456
lookup: None,
5557
snippet: None,
5658
kind: None,
@@ -60,6 +62,10 @@ impl CompletionItem {
6062
pub fn label(&self) -> &str {
6163
&self.label
6264
}
65+
/// Short one-line additional information, like a type
66+
pub fn detail(&self) -> Option<&str> {
67+
self.detail.as_ref().map(|it| it.as_str())
68+
}
6369
/// What string is used for filtering.
6470
pub fn lookup(&self) -> &str {
6571
self.lookup
@@ -87,6 +93,7 @@ impl CompletionItem {
8793
pub(crate) struct Builder {
8894
completion_kind: CompletionKind,
8995
label: String,
96+
detail: Option<String>,
9097
lookup: Option<String>,
9198
snippet: Option<String>,
9299
kind: Option<CompletionItemKind>,
@@ -100,6 +107,7 @@ impl Builder {
100107
pub(crate) fn build(self) -> CompletionItem {
101108
CompletionItem {
102109
label: self.label,
110+
detail: self.detail,
103111
lookup: self.lookup,
104112
snippet: self.snippet,
105113
kind: self.kind,
@@ -118,6 +126,14 @@ impl Builder {
118126
self.kind = Some(kind);
119127
self
120128
}
129+
#[allow(unused)]
130+
pub(crate) fn detail(self, detail: impl Into<String>) -> Builder {
131+
self.set_detail(Some(detail))
132+
}
133+
pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder {
134+
self.detail = detail.map(Into::into);
135+
self
136+
}
121137
pub(super) fn from_resolution(
122138
mut self,
123139
ctx: &CompletionContext,
@@ -227,6 +243,9 @@ impl Completions {
227243
} else {
228244
res.push_str(&c.label);
229245
}
246+
if let Some(detail) = &c.detail {
247+
res.push_str(&format!(" {:?}", detail));
248+
}
230249
if let Some(snippet) = &c.snippet {
231250
res.push_str(&format!(" {:?}", snippet));
232251
}

crates/ra_lsp_server/src/conv.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ impl Conv for CompletionItem {
7575
fn conv(self) -> <Self as Conv>::Output {
7676
let mut res = ::languageserver_types::CompletionItem {
7777
label: self.label().to_string(),
78+
detail: self.detail().map(|it| it.to_string()),
7879
filter_text: Some(self.lookup().to_string()),
7980
kind: self.kind().map(|it| it.conv()),
8081
..Default::default()

0 commit comments

Comments
 (0)