Skip to content

Commit

Permalink
Merge #801
Browse files Browse the repository at this point in the history
801: Implement completion for associated items r=matklad a=lnicola

Fixes #747.

r? @matklad

Co-authored-by: Laurențiu Nicola <lnicola@dend.ro>
  • Loading branch information
bors[bot] and lnicola committed Feb 12, 2019
2 parents 3714800 + 7e8527f commit 19718ea
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 1 deletion.
20 changes: 20 additions & 0 deletions crates/ra_hir/src/ty/method_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
22 changes: 22 additions & 0 deletions crates/ra_ide_api/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
104 changes: 103 additions & 1 deletion crates/ra_ide_api/src/completion/complete_path.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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,
};
}
Expand Down Expand Up @@ -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(
Expand Down
34 changes: 34 additions & 0 deletions crates/ra_ide_api/src/completion/completion_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand 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 {
Expand Down Expand Up @@ -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};
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
]
Original file line number Diff line number Diff line change
@@ -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
}
]
Original file line number Diff line number Diff line change
@@ -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
}
]

0 comments on commit 19718ea

Please sign in to comment.