Merge #801
801: Implement completion for associated items r=matklad a=lnicola Fixes #747. r? @matklad Co-authored-by: Laurențiu Nicola <lnicola@dend.ro>
This commit is contained in:
commit
19718ea109
@ -174,4 +174,24 @@ impl Ty {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// This would be nicer if it just returned an iterator, but that runs into
|
||||
// lifetime problems, because we need to borrow temp `CrateImplBlocks`.
|
||||
pub fn iterate_impl_items<T>(
|
||||
self,
|
||||
db: &impl HirDatabase,
|
||||
mut callback: impl FnMut(ImplItem) -> Option<T>,
|
||||
) -> Option<T> {
|
||||
let krate = def_crate(db, &self)?;
|
||||
let impls = db.impls_in_crate(krate);
|
||||
|
||||
for (_, impl_block) in impls.lookup_impl_blocks(db, &self) {
|
||||
for item in impl_block.items() {
|
||||
if let Some(result) = callback(*item) {
|
||||
return Some(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -80,3 +80,25 @@ pub fn function_label(node: &ast::FnDef) -> Option<String> {
|
||||
|
||||
Some(label.trim().to_owned())
|
||||
}
|
||||
|
||||
pub fn const_label(node: &ast::ConstDef) -> String {
|
||||
let label: String = node
|
||||
.syntax()
|
||||
.children()
|
||||
.filter(|child| ast::Comment::cast(child).is_none())
|
||||
.map(|node| node.text().to_string())
|
||||
.collect();
|
||||
|
||||
label.trim().to_owned()
|
||||
}
|
||||
|
||||
pub fn type_label(node: &ast::TypeDef) -> String {
|
||||
let label: String = node
|
||||
.syntax()
|
||||
.children()
|
||||
.filter(|child| ast::Comment::cast(child).is_none())
|
||||
.map(|node| node.text().to_string())
|
||||
.collect();
|
||||
|
||||
label.trim().to_owned()
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use join_to_string::join;
|
||||
use hir::{Docs, Resolution};
|
||||
use ra_syntax::AstNode;
|
||||
use ra_syntax::{AstNode, ast::NameOwner};
|
||||
use test_utils::tested_by;
|
||||
|
||||
use crate::completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext};
|
||||
@ -58,6 +58,51 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
}
|
||||
});
|
||||
}
|
||||
hir::ModuleDef::Struct(s) => {
|
||||
let ty = s.ty(ctx.db);
|
||||
ty.iterate_impl_items(ctx.db, |item| match item {
|
||||
hir::ImplItem::Method(func) => {
|
||||
let sig = func.signature(ctx.db);
|
||||
if !sig.has_self_param() {
|
||||
CompletionItem::new(
|
||||
CompletionKind::Reference,
|
||||
ctx.source_range(),
|
||||
sig.name().to_string(),
|
||||
)
|
||||
.from_function(ctx, func)
|
||||
.kind(CompletionItemKind::Method)
|
||||
.add_to(acc);
|
||||
}
|
||||
None::<()>
|
||||
}
|
||||
hir::ImplItem::Const(ct) => {
|
||||
let source = ct.source(ctx.db);
|
||||
if let Some(name) = source.1.name() {
|
||||
CompletionItem::new(
|
||||
CompletionKind::Reference,
|
||||
ctx.source_range(),
|
||||
name.text().to_string(),
|
||||
)
|
||||
.from_const(ctx, ct)
|
||||
.add_to(acc);
|
||||
}
|
||||
None::<()>
|
||||
}
|
||||
hir::ImplItem::Type(ty) => {
|
||||
let source = ty.source(ctx.db);
|
||||
if let Some(name) = source.1.name() {
|
||||
CompletionItem::new(
|
||||
CompletionKind::Reference,
|
||||
ctx.source_range(),
|
||||
name.text().to_string(),
|
||||
)
|
||||
.from_type(ctx, ty)
|
||||
.add_to(acc);
|
||||
}
|
||||
None::<()>
|
||||
}
|
||||
});
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
}
|
||||
@ -197,6 +242,63 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_struct_associated_method() {
|
||||
check_reference_completion(
|
||||
"struct_associated_method",
|
||||
"
|
||||
//- /lib.rs
|
||||
/// A Struct
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
/// An associated method
|
||||
fn m() { }
|
||||
}
|
||||
|
||||
fn foo() { let _ = S::<|> }
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_struct_associated_const() {
|
||||
check_reference_completion(
|
||||
"struct_associated_const",
|
||||
"
|
||||
//- /lib.rs
|
||||
/// A Struct
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
/// An associated const
|
||||
const C: i32 = 42;
|
||||
}
|
||||
|
||||
fn foo() { let _ = S::<|> }
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_struct_associated_type() {
|
||||
check_reference_completion(
|
||||
"struct_associated_type",
|
||||
"
|
||||
//- /lib.rs
|
||||
/// A Struct
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
/// An associated type
|
||||
type T = i32;
|
||||
}
|
||||
|
||||
fn foo() { let _ = S::<|> }
|
||||
",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_use_paths_across_crates() {
|
||||
check_reference_completion(
|
||||
|
@ -8,6 +8,8 @@ use test_utils::tested_by;
|
||||
use crate::completion::{
|
||||
completion_context::CompletionContext,
|
||||
function_label,
|
||||
const_label,
|
||||
type_label
|
||||
};
|
||||
|
||||
/// `CompletionItem` describes a single completion variant in the editor pop-up.
|
||||
@ -267,6 +269,28 @@ impl Builder {
|
||||
self.kind = Some(CompletionItemKind::Function);
|
||||
self
|
||||
}
|
||||
|
||||
pub(super) fn from_const(mut self, ctx: &CompletionContext, ct: hir::Const) -> Builder {
|
||||
if let Some(docs) = ct.docs(ctx.db) {
|
||||
self.documentation = Some(docs);
|
||||
}
|
||||
|
||||
self.detail = Some(const_item_label(ctx, ct));
|
||||
self.kind = Some(CompletionItemKind::Const);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub(super) fn from_type(mut self, ctx: &CompletionContext, ty: hir::Type) -> Builder {
|
||||
if let Some(docs) = ty.docs(ctx.db) {
|
||||
self.documentation = Some(docs);
|
||||
}
|
||||
|
||||
self.detail = Some(type_item_label(ctx, ty));
|
||||
self.kind = Some(CompletionItemKind::TypeAlias);
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Into<CompletionItem> for Builder {
|
||||
@ -305,6 +329,16 @@ fn function_item_label(ctx: &CompletionContext, function: hir::Function) -> Opti
|
||||
function_label(&node)
|
||||
}
|
||||
|
||||
fn const_item_label(ctx: &CompletionContext, ct: hir::Const) -> String {
|
||||
let node = ct.source(ctx.db).1;
|
||||
const_label(&node)
|
||||
}
|
||||
|
||||
fn type_item_label(ctx: &CompletionContext, ty: hir::Type) -> String {
|
||||
let node = ty.source(ctx.db).1;
|
||||
type_label(&node)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
|
||||
use crate::mock_analysis::{single_file_with_position, analysis_and_position};
|
||||
|
@ -0,0 +1,28 @@
|
||||
---
|
||||
created: "2019-02-12T09:57:51.107816726Z"
|
||||
creator: insta@0.6.2
|
||||
source: crates/ra_ide_api/src/completion/completion_item.rs
|
||||
expression: kind_completions
|
||||
---
|
||||
[
|
||||
CompletionItem {
|
||||
completion_kind: Reference,
|
||||
label: "C",
|
||||
kind: Some(
|
||||
Const
|
||||
),
|
||||
detail: Some(
|
||||
"const C: i32 = 42;"
|
||||
),
|
||||
documentation: Some(
|
||||
Documentation(
|
||||
"An associated const"
|
||||
)
|
||||
),
|
||||
lookup: None,
|
||||
insert_text: None,
|
||||
insert_text_format: PlainText,
|
||||
source_range: [107; 107),
|
||||
text_edit: None
|
||||
}
|
||||
]
|
@ -0,0 +1,30 @@
|
||||
---
|
||||
created: "2019-02-12T09:57:51.106389138Z"
|
||||
creator: insta@0.6.2
|
||||
source: crates/ra_ide_api/src/completion/completion_item.rs
|
||||
expression: kind_completions
|
||||
---
|
||||
[
|
||||
CompletionItem {
|
||||
completion_kind: Reference,
|
||||
label: "m",
|
||||
kind: Some(
|
||||
Method
|
||||
),
|
||||
detail: Some(
|
||||
"fn m()"
|
||||
),
|
||||
documentation: Some(
|
||||
Documentation(
|
||||
"An associated method"
|
||||
)
|
||||
),
|
||||
lookup: None,
|
||||
insert_text: Some(
|
||||
"m()$0"
|
||||
),
|
||||
insert_text_format: Snippet,
|
||||
source_range: [100; 100),
|
||||
text_edit: None
|
||||
}
|
||||
]
|
@ -0,0 +1,28 @@
|
||||
---
|
||||
created: "2019-02-12T09:33:54.719956203Z"
|
||||
creator: insta@0.6.2
|
||||
source: crates/ra_ide_api/src/completion/completion_item.rs
|
||||
expression: kind_completions
|
||||
---
|
||||
[
|
||||
CompletionItem {
|
||||
completion_kind: Reference,
|
||||
label: "T",
|
||||
kind: Some(
|
||||
TypeAlias
|
||||
),
|
||||
detail: Some(
|
||||
"type T = i32;"
|
||||
),
|
||||
documentation: Some(
|
||||
Documentation(
|
||||
"An associated type"
|
||||
)
|
||||
),
|
||||
lookup: None,
|
||||
insert_text: None,
|
||||
insert_text_format: PlainText,
|
||||
source_range: [101; 101),
|
||||
text_edit: None
|
||||
}
|
||||
]
|
Loading…
x
Reference in New Issue
Block a user