mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-11-03 13:13:18 +00:00 
			
		
		
		
	Implement completion for associated items
This commit is contained in:
		
							parent
							
								
									37148000dc
								
							
						
					
					
						commit
						7e8527f748
					
				@ -174,4 +174,24 @@ impl Ty {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        None
 | 
					        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())
 | 
					    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 join_to_string::join;
 | 
				
			||||||
use hir::{Docs, Resolution};
 | 
					use hir::{Docs, Resolution};
 | 
				
			||||||
use ra_syntax::AstNode;
 | 
					use ra_syntax::{AstNode, ast::NameOwner};
 | 
				
			||||||
use test_utils::tested_by;
 | 
					use test_utils::tested_by;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext};
 | 
					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,
 | 
					        _ => 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]
 | 
					    #[test]
 | 
				
			||||||
    fn completes_use_paths_across_crates() {
 | 
					    fn completes_use_paths_across_crates() {
 | 
				
			||||||
        check_reference_completion(
 | 
					        check_reference_completion(
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,8 @@ use test_utils::tested_by;
 | 
				
			|||||||
use crate::completion::{
 | 
					use crate::completion::{
 | 
				
			||||||
    completion_context::CompletionContext,
 | 
					    completion_context::CompletionContext,
 | 
				
			||||||
    function_label,
 | 
					    function_label,
 | 
				
			||||||
 | 
					    const_label,
 | 
				
			||||||
 | 
					    type_label
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// `CompletionItem` describes a single completion variant in the editor pop-up.
 | 
					/// `CompletionItem` describes a single completion variant in the editor pop-up.
 | 
				
			||||||
@ -267,6 +269,28 @@ impl Builder {
 | 
				
			|||||||
        self.kind = Some(CompletionItemKind::Function);
 | 
					        self.kind = Some(CompletionItemKind::Function);
 | 
				
			||||||
        self
 | 
					        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 {
 | 
					impl<'a> Into<CompletionItem> for Builder {
 | 
				
			||||||
@ -305,6 +329,16 @@ fn function_item_label(ctx: &CompletionContext, function: hir::Function) -> Opti
 | 
				
			|||||||
    function_label(&node)
 | 
					    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)]
 | 
					#[cfg(test)]
 | 
				
			||||||
pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
 | 
					pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
 | 
				
			||||||
    use crate::mock_analysis::{single_file_with_position, analysis_and_position};
 | 
					    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