mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
Merge #475
475: Show types of fields in completion r=matklad a=matklad  r? @flodiebold Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
aca14c591f
@ -4,7 +4,7 @@ use ra_db::Cancelable;
|
||||
use ra_syntax::ast::{self, NameOwner, StructFlavor, AstNode};
|
||||
|
||||
use crate::{
|
||||
DefId, Name, AsName, Struct, Enum, VariantData, StructField, HirDatabase, DefKind,
|
||||
DefId, Name, AsName, Struct, Enum, HirDatabase, DefKind,
|
||||
type_ref::TypeRef,
|
||||
};
|
||||
|
||||
@ -12,6 +12,10 @@ impl Struct {
|
||||
pub(crate) fn new(def_id: DefId) -> Self {
|
||||
Struct { def_id }
|
||||
}
|
||||
|
||||
pub(crate) fn variant_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<VariantData>> {
|
||||
Ok(db.struct_data(self.def_id)?.variant_data.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@ -83,6 +87,51 @@ impl EnumData {
|
||||
}
|
||||
}
|
||||
|
||||
/// A single field of an enum variant or struct
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct StructField {
|
||||
pub(crate) name: Name,
|
||||
pub(crate) type_ref: TypeRef,
|
||||
}
|
||||
|
||||
/// Fields of an enum variant or struct
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum VariantData {
|
||||
Struct(Vec<StructField>),
|
||||
Tuple(Vec<StructField>),
|
||||
Unit,
|
||||
}
|
||||
|
||||
impl VariantData {
|
||||
pub fn fields(&self) -> &[StructField] {
|
||||
match self {
|
||||
VariantData::Struct(fields) | VariantData::Tuple(fields) => fields,
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_struct(&self) -> bool {
|
||||
match self {
|
||||
VariantData::Struct(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_tuple(&self) -> bool {
|
||||
match self {
|
||||
VariantData::Tuple(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_unit(&self) -> bool {
|
||||
match self {
|
||||
VariantData::Unit => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VariantData {
|
||||
fn new(flavor: StructFlavor) -> Self {
|
||||
match flavor {
|
||||
@ -114,7 +163,7 @@ impl VariantData {
|
||||
pub(crate) fn get_field_type_ref(&self, field_name: &Name) -> Option<&TypeRef> {
|
||||
self.fields()
|
||||
.iter()
|
||||
.find(|f| f.name() == field_name)
|
||||
.map(|f| f.type_ref())
|
||||
.find(|f| f.name == *field_name)
|
||||
.map(|f| &f.type_ref)
|
||||
}
|
||||
}
|
||||
|
@ -5,12 +5,13 @@ use ra_db::{CrateId, Cancelable, FileId};
|
||||
use ra_syntax::{ast, TreePtr, SyntaxNode};
|
||||
|
||||
use crate::{
|
||||
Name, DefId, Path, PerNs, ScopesWithSyntaxMapping,
|
||||
Name, DefId, Path, PerNs, ScopesWithSyntaxMapping, Ty,
|
||||
type_ref::TypeRef,
|
||||
nameres::ModuleScope,
|
||||
db::HirDatabase,
|
||||
expr::BodySyntaxMapping,
|
||||
ty::InferenceResult,
|
||||
adt::VariantData,
|
||||
};
|
||||
|
||||
/// hir::Crate describes a single crate. It's the main interface with which
|
||||
@ -137,58 +138,18 @@ impl Module {
|
||||
}
|
||||
}
|
||||
|
||||
/// A single field of an enum variant or struct
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct StructField {
|
||||
pub(crate) name: Name,
|
||||
pub(crate) type_ref: TypeRef,
|
||||
struct_: Struct,
|
||||
name: Name,
|
||||
}
|
||||
|
||||
impl StructField {
|
||||
pub fn name(&self) -> &Name {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn type_ref(&self) -> &TypeRef {
|
||||
&self.type_ref
|
||||
}
|
||||
}
|
||||
|
||||
/// Fields of an enum variant or struct
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum VariantData {
|
||||
Struct(Vec<StructField>),
|
||||
Tuple(Vec<StructField>),
|
||||
Unit,
|
||||
}
|
||||
|
||||
impl VariantData {
|
||||
pub fn fields(&self) -> &[StructField] {
|
||||
match self {
|
||||
VariantData::Struct(fields) | VariantData::Tuple(fields) => fields,
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_struct(&self) -> bool {
|
||||
match self {
|
||||
VariantData::Struct(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_tuple(&self) -> bool {
|
||||
match self {
|
||||
VariantData::Tuple(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_unit(&self) -> bool {
|
||||
match self {
|
||||
VariantData::Unit => true,
|
||||
_ => false,
|
||||
}
|
||||
pub fn ty(&self, db: &impl HirDatabase) -> Cancelable<Option<Ty>> {
|
||||
db.type_for_field(self.struct_.def_id, self.name.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,8 +167,18 @@ impl Struct {
|
||||
Ok(db.struct_data(self.def_id)?.name.clone())
|
||||
}
|
||||
|
||||
pub fn variant_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<VariantData>> {
|
||||
Ok(db.struct_data(self.def_id)?.variant_data.clone())
|
||||
pub fn fields(&self, db: &impl HirDatabase) -> Cancelable<Vec<StructField>> {
|
||||
let res = db
|
||||
.struct_data(self.def_id)?
|
||||
.variant_data
|
||||
.fields()
|
||||
.iter()
|
||||
.map(|it| StructField {
|
||||
struct_: self.clone(),
|
||||
name: it.name.clone(),
|
||||
})
|
||||
.collect();
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,6 @@ pub use self::code_model_api::{
|
||||
Crate, CrateDependency,
|
||||
Def,
|
||||
Module, ModuleSource, Problem,
|
||||
Struct, Enum, VariantData, StructField,
|
||||
Struct, Enum,
|
||||
Function, FnSignature,
|
||||
};
|
||||
|
@ -28,13 +28,13 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
|
||||
Ty::Adt { def_id, .. } => {
|
||||
match def_id.resolve(ctx.db)? {
|
||||
Def::Struct(s) => {
|
||||
let variant_data = s.variant_data(ctx.db)?;
|
||||
for field in variant_data.fields() {
|
||||
for field in s.fields(ctx.db)? {
|
||||
CompletionItem::new(
|
||||
CompletionKind::Reference,
|
||||
field.name().to_string(),
|
||||
)
|
||||
.kind(CompletionItemKind::Field)
|
||||
.set_detail(field.ty(ctx.db)?.map(|ty| ty.to_string()))
|
||||
.add_to(acc);
|
||||
}
|
||||
}
|
||||
@ -72,7 +72,7 @@ mod tests {
|
||||
a.<|>
|
||||
}
|
||||
",
|
||||
r#"the_field"#,
|
||||
r#"the_field "u32""#,
|
||||
);
|
||||
}
|
||||
|
||||
@ -80,14 +80,14 @@ mod tests {
|
||||
fn test_struct_field_completion_self() {
|
||||
check_ref_completion(
|
||||
r"
|
||||
struct A { the_field: u32 }
|
||||
struct A { the_field: (u32,) }
|
||||
impl A {
|
||||
fn foo(self) {
|
||||
self.<|>
|
||||
}
|
||||
}
|
||||
",
|
||||
r#"the_field"#,
|
||||
r#"the_field "(u32,)""#,
|
||||
);
|
||||
}
|
||||
|
||||
@ -95,14 +95,14 @@ mod tests {
|
||||
fn test_struct_field_completion_autoderef() {
|
||||
check_ref_completion(
|
||||
r"
|
||||
struct A { the_field: u32 }
|
||||
struct A { the_field: (u32, i32) }
|
||||
impl A {
|
||||
fn foo(&self) {
|
||||
self.<|>
|
||||
}
|
||||
}
|
||||
",
|
||||
r#"the_field"#,
|
||||
r#"the_field "(u32, i32)""#,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ pub struct CompletionItem {
|
||||
/// completion.
|
||||
completion_kind: CompletionKind,
|
||||
label: String,
|
||||
detail: Option<String>,
|
||||
lookup: Option<String>,
|
||||
snippet: Option<String>,
|
||||
kind: Option<CompletionItemKind>,
|
||||
@ -51,6 +52,7 @@ impl CompletionItem {
|
||||
Builder {
|
||||
completion_kind,
|
||||
label,
|
||||
detail: None,
|
||||
lookup: None,
|
||||
snippet: None,
|
||||
kind: None,
|
||||
@ -60,6 +62,10 @@ impl CompletionItem {
|
||||
pub fn label(&self) -> &str {
|
||||
&self.label
|
||||
}
|
||||
/// Short one-line additional information, like a type
|
||||
pub fn detail(&self) -> Option<&str> {
|
||||
self.detail.as_ref().map(|it| it.as_str())
|
||||
}
|
||||
/// What string is used for filtering.
|
||||
pub fn lookup(&self) -> &str {
|
||||
self.lookup
|
||||
@ -87,6 +93,7 @@ impl CompletionItem {
|
||||
pub(crate) struct Builder {
|
||||
completion_kind: CompletionKind,
|
||||
label: String,
|
||||
detail: Option<String>,
|
||||
lookup: Option<String>,
|
||||
snippet: Option<String>,
|
||||
kind: Option<CompletionItemKind>,
|
||||
@ -100,6 +107,7 @@ impl Builder {
|
||||
pub(crate) fn build(self) -> CompletionItem {
|
||||
CompletionItem {
|
||||
label: self.label,
|
||||
detail: self.detail,
|
||||
lookup: self.lookup,
|
||||
snippet: self.snippet,
|
||||
kind: self.kind,
|
||||
@ -118,6 +126,14 @@ impl Builder {
|
||||
self.kind = Some(kind);
|
||||
self
|
||||
}
|
||||
#[allow(unused)]
|
||||
pub(crate) fn detail(self, detail: impl Into<String>) -> Builder {
|
||||
self.set_detail(Some(detail))
|
||||
}
|
||||
pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder {
|
||||
self.detail = detail.map(Into::into);
|
||||
self
|
||||
}
|
||||
pub(super) fn from_resolution(
|
||||
mut self,
|
||||
ctx: &CompletionContext,
|
||||
@ -227,6 +243,9 @@ impl Completions {
|
||||
} else {
|
||||
res.push_str(&c.label);
|
||||
}
|
||||
if let Some(detail) = &c.detail {
|
||||
res.push_str(&format!(" {:?}", detail));
|
||||
}
|
||||
if let Some(snippet) = &c.snippet {
|
||||
res.push_str(&format!(" {:?}", snippet));
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ impl Conv for CompletionItem {
|
||||
fn conv(self) -> <Self as Conv>::Output {
|
||||
let mut res = ::languageserver_types::CompletionItem {
|
||||
label: self.label().to_string(),
|
||||
detail: self.detail().map(|it| it.to_string()),
|
||||
filter_text: Some(self.lookup().to_string()),
|
||||
kind: self.kind().map(|it| it.conv()),
|
||||
..Default::default()
|
||||
|
Loading…
Reference in New Issue
Block a user