aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/handlers/auto_import.rs41
-rw-r--r--crates/assists/src/handlers/generate_function.rs19
-rw-r--r--crates/assists/src/handlers/generate_impl.rs11
-rw-r--r--crates/assists/src/handlers/generate_new.rs8
-rw-r--r--crates/assists/src/handlers/introduce_named_lifetime.rs2
-rw-r--r--crates/assists/src/handlers/qualify_path.rs43
-rw-r--r--crates/assists/src/handlers/raw_string.rs2
-rw-r--r--crates/assists/src/handlers/replace_derive_with_manual_impl.rs19
-rw-r--r--crates/assists/src/utils.rs2
-rw-r--r--crates/base_db/src/input.rs2
-rw-r--r--crates/completion/src/completions/attribute.rs9
-rw-r--r--crates/completion/src/completions/flyimport.rs452
-rw-r--r--crates/completion/src/completions/fn_param.rs4
-rw-r--r--crates/completion/src/completions/mod_.rs10
-rw-r--r--crates/completion/src/completions/record.rs8
-rw-r--r--crates/completion/src/completions/trait_impl.rs8
-rw-r--r--crates/completion/src/completions/unqualified_path.rs60
-rw-r--r--crates/completion/src/config.rs2
-rw-r--r--crates/completion/src/item.rs99
-rw-r--r--crates/completion/src/lib.rs11
-rw-r--r--crates/completion/src/render.rs191
-rw-r--r--crates/completion/src/render/const_.rs10
-rw-r--r--crates/completion/src/render/enum_variant.rs5
-rw-r--r--crates/completion/src/render/function.rs7
-rw-r--r--crates/completion/src/render/macro_.rs5
-rw-r--r--crates/completion/src/render/type_alias.rs10
-rw-r--r--crates/completion/src/test_utils.rs5
-rw-r--r--crates/hir/src/attrs.rs6
-rw-r--r--crates/hir/src/code_model.rs41
-rw-r--r--crates/hir/src/db.rs14
-rw-r--r--crates/hir/src/has_source.rs6
-rw-r--r--crates/hir/src/semantics.rs2
-rw-r--r--crates/hir/src/semantics/source_to_def.rs3
-rw-r--r--crates/hir_def/src/attr.rs3
-rw-r--r--crates/hir_def/src/body.rs8
-rw-r--r--crates/hir_def/src/body/tests.rs41
-rw-r--r--crates/hir_def/src/child_by_source.rs2
-rw-r--r--crates/hir_def/src/db.rs17
-rw-r--r--crates/hir_def/src/find_path.rs32
-rw-r--r--crates/hir_def/src/import_map.rs70
-rw-r--r--crates/hir_def/src/item_tree.rs41
-rw-r--r--crates/hir_def/src/item_tree/lower.rs45
-rw-r--r--crates/hir_def/src/lang_item.rs2
-rw-r--r--crates/hir_def/src/lib.rs12
-rw-r--r--crates/hir_def/src/nameres.rs150
-rw-r--r--crates/hir_def/src/nameres/collector.rs70
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs45
-rw-r--r--crates/hir_def/src/nameres/tests.rs22
-rw-r--r--crates/hir_def/src/nameres/tests/block.rs97
-rw-r--r--crates/hir_def/src/path.rs2
-rw-r--r--crates/hir_def/src/resolver.rs66
-rw-r--r--crates/hir_def/src/test_db.rs6
-rw-r--r--crates/hir_def/src/type_ref.rs2
-rw-r--r--crates/hir_def/src/visibility.rs8
-rw-r--r--crates/hir_expand/src/ast_id_map.rs20
-rw-r--r--crates/hir_expand/src/builtin_derive.rs2
-rw-r--r--crates/hir_expand/src/db.rs2
-rw-r--r--crates/hir_expand/src/hygiene.rs2
-rw-r--r--crates/hir_expand/src/name.rs8
-rw-r--r--crates/hir_expand/src/proc_macro.rs4
-rw-r--r--crates/hir_ty/Cargo.toml6
-rw-r--r--crates/hir_ty/src/diagnostics.rs2
-rw-r--r--crates/hir_ty/src/infer/expr.rs5
-rw-r--r--crates/hir_ty/src/method_resolution.rs4
-rw-r--r--crates/hir_ty/src/test_db.rs4
-rw-r--r--crates/hir_ty/src/tests.rs16
-rw-r--r--crates/hir_ty/src/tests/simple.rs24
-rw-r--r--crates/ide/src/call_hierarchy.rs2
-rw-r--r--crates/ide/src/diagnostics/fixes.rs2
-rw-r--r--crates/ide/src/display/navigation_target.rs43
-rw-r--r--crates/ide/src/display/short_label.rs10
-rw-r--r--crates/ide/src/doc_links.rs31
-rw-r--r--crates/ide/src/extend_selection.rs4
-rw-r--r--crates/ide/src/file_structure.rs3
-rw-r--r--crates/ide/src/goto_definition.rs95
-rw-r--r--crates/ide/src/hover.rs42
-rw-r--r--crates/ide/src/inlay_hints.rs2
-rw-r--r--crates/ide/src/join_lines.rs2
-rw-r--r--crates/ide/src/lib.rs23
-rw-r--r--crates/ide/src/references.rs72
-rw-r--r--crates/ide/src/references/rename.rs676
-rw-r--r--crates/ide/src/runnables.rs234
-rw-r--r--crates/ide/src/status.rs2
-rw-r--r--crates/ide/src/syntax_highlighting.rs4
-rw-r--r--crates/ide/src/syntax_highlighting/format.rs5
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs26
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs2
-rw-r--r--crates/ide/src/syntax_tree.rs28
-rw-r--r--crates/ide_db/src/apply_change.rs1
-rw-r--r--crates/ide_db/src/defs.rs13
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs356
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs2
-rw-r--r--crates/ide_db/src/helpers/insert_use/tests.rs2
-rw-r--r--crates/ide_db/src/imports_locator.rs76
-rw-r--r--crates/ide_db/src/lib.rs24
-rw-r--r--crates/ide_db/src/search.rs10
-rw-r--r--crates/ide_db/src/symbol_index.rs6
-rw-r--r--crates/mbe/src/syntax_bridge.rs36
-rw-r--r--crates/mbe/src/tests.rs10
-rw-r--r--crates/parser/src/event.rs5
-rw-r--r--crates/parser/src/grammar.rs12
-rw-r--r--crates/parser/src/grammar/items.rs2
-rw-r--r--crates/parser/src/grammar/items/traits.rs4
-rw-r--r--crates/parser/src/grammar/params.rs31
-rw-r--r--crates/parser/src/syntax_kind.rs3
-rw-r--r--crates/parser/src/syntax_kind/generated.rs1
-rw-r--r--crates/proc_macro_api/Cargo.toml2
-rw-r--r--crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt8
-rw-r--r--crates/proc_macro_srv/src/tests/mod.rs8
-rw-r--r--crates/proc_macro_srv/src/tests/utils.rs2
-rw-r--r--crates/profile/Cargo.toml3
-rw-r--r--crates/profile/src/hprof.rs4
-rw-r--r--crates/profile/src/lib.rs7
-rw-r--r--crates/profile/src/memory_usage.rs7
-rw-r--r--crates/project_model/Cargo.toml1
-rw-r--r--crates/project_model/src/build_data.rs206
-rw-r--r--crates/project_model/src/cargo_workspace.rs208
-rw-r--r--crates/project_model/src/lib.rs2
-rw-r--r--crates/project_model/src/rustc_cfg.rs34
-rw-r--r--crates/project_model/src/workspace.rs143
-rw-r--r--crates/rust-analyzer/Cargo.toml8
-rw-r--r--crates/rust-analyzer/src/bin/args.rs23
-rw-r--r--crates/rust-analyzer/src/bin/main.rs4
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs2
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs5
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs2
-rw-r--r--crates/rust-analyzer/src/config.rs15
-rw-r--r--crates/rust-analyzer/src/handlers.rs27
-rw-r--r--crates/rust-analyzer/src/reload.rs16
-rw-r--r--crates/rust-analyzer/src/to_proto.rs47
-rw-r--r--crates/ssr/src/matching.rs13
-rw-r--r--crates/ssr/src/replacing.rs2
-rw-r--r--crates/ssr/src/resolving.rs2
-rw-r--r--crates/stdx/src/lib.rs2
-rw-r--r--crates/syntax/Cargo.toml7
-rw-r--r--crates/syntax/src/algo.rs7
-rw-r--r--crates/syntax/src/ast.rs4
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs40
-rw-r--r--crates/syntax/src/ast/make.rs8
-rw-r--r--crates/syntax/src/ast/node_ext.rs43
-rw-r--r--crates/syntax/src/ast/token_ext.rs12
-rw-r--r--crates/syntax/src/lib.rs4
-rw-r--r--crates/syntax/src/parsing/reparsing.rs3
-rw-r--r--crates/syntax/src/parsing/text_tree_sink.rs4
-rw-r--r--crates/syntax/src/syntax_node.rs4
-rw-r--r--crates/syntax/src/validation.rs2
-rw-r--r--crates/syntax/test_data/parser/err/0037_visibility_in_traits.rast10
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0006_self_param.rast15
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0018_arb_self_types.rast6
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0021_impl_item_list.rast3
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0022_crate_visibility.rast50
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0022_crate_visibility.rs3
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast3
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0160_crate_visibility_in.rast42
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0160_crate_visibility_in.rs2
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0161_impl_def_const.rast24
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0161_impl_def_const.rs1
-rw-r--r--crates/syntax/test_data/parser/ok/0007_extern_crate.rast3
-rw-r--r--crates/syntax/test_data/parser/ok/0012_visibility.rast10
-rw-r--r--crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rast3
-rw-r--r--crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast24
162 files changed, 3259 insertions, 1742 deletions
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs
index 4e2a4fcd9..e93901cb3 100644
--- a/crates/assists/src/handlers/auto_import.rs
+++ b/crates/assists/src/handlers/auto_import.rs
@@ -3,7 +3,7 @@ use ide_db::helpers::{
3 insert_use::{insert_use, ImportScope}, 3 insert_use::{insert_use, ImportScope},
4 mod_path_to_ast, 4 mod_path_to_ast,
5}; 5};
6use syntax::ast; 6use syntax::{ast, AstNode, SyntaxNode};
7 7
8use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; 8use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
9 9
@@ -82,25 +82,16 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
82// # pub mod std { pub mod collections { pub struct HashMap { } } } 82// # pub mod std { pub mod collections { pub struct HashMap { } } }
83// ``` 83// ```
84pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 84pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
85 let import_assets = 85 let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
86 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() { 86 let proposed_imports =
87 ImportAssets::for_regular_path(path_under_caret, &ctx.sema) 87 import_assets.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind);
88 } else if let Some(method_under_caret) =
89 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
90 {
91 ImportAssets::for_method_call(method_under_caret, &ctx.sema)
92 } else {
93 None
94 }?;
95 let proposed_imports = import_assets.search_for_imports(&ctx.sema, &ctx.config.insert_use);
96 if proposed_imports.is_empty() { 88 if proposed_imports.is_empty() {
97 return None; 89 return None;
98 } 90 }
99 91
100 let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; 92 let range = ctx.sema.original_range(&syntax_under_caret).range;
101 let group = import_group_message(import_assets.import_candidate()); 93 let group = import_group_message(import_assets.import_candidate());
102 let scope = 94 let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?;
103 ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), &ctx.sema)?;
104 for (import, _) in proposed_imports { 95 for (import, _) in proposed_imports {
105 acc.add_group( 96 acc.add_group(
106 &group, 97 &group,
@@ -117,14 +108,28 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
117 Some(()) 108 Some(())
118} 109}
119 110
111pub(super) fn find_importable_node(ctx: &AssistContext) -> Option<(ImportAssets, SyntaxNode)> {
112 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
113 ImportAssets::for_exact_path(&path_under_caret, &ctx.sema)
114 .zip(Some(path_under_caret.syntax().clone()))
115 } else if let Some(method_under_caret) =
116 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
117 {
118 ImportAssets::for_method_call(&method_under_caret, &ctx.sema)
119 .zip(Some(method_under_caret.syntax().clone()))
120 } else {
121 None
122 }
123}
124
120fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel { 125fn import_group_message(import_candidate: &ImportCandidate) -> GroupLabel {
121 let name = match import_candidate { 126 let name = match import_candidate {
122 ImportCandidate::Path(candidate) => format!("Import {}", &candidate.name), 127 ImportCandidate::Path(candidate) => format!("Import {}", candidate.name.text()),
123 ImportCandidate::TraitAssocItem(candidate) => { 128 ImportCandidate::TraitAssocItem(candidate) => {
124 format!("Import a trait for item {}", &candidate.name) 129 format!("Import a trait for item {}", candidate.name.text())
125 } 130 }
126 ImportCandidate::TraitMethod(candidate) => { 131 ImportCandidate::TraitMethod(candidate) => {
127 format!("Import a trait for method {}", &candidate.name) 132 format!("Import a trait for method {}", candidate.name.text())
128 } 133 }
129 }; 134 };
130 GroupLabel(name) 135 GroupLabel(name)
diff --git a/crates/assists/src/handlers/generate_function.rs b/crates/assists/src/handlers/generate_function.rs
index 06ac85f67..1805c1dfd 100644
--- a/crates/assists/src/handlers/generate_function.rs
+++ b/crates/assists/src/handlers/generate_function.rs
@@ -158,11 +158,11 @@ impl FunctionBuilder {
158 it.text_range().end() 158 it.text_range().end()
159 } 159 }
160 GeneratedFunctionTarget::InEmptyItemList(it) => { 160 GeneratedFunctionTarget::InEmptyItemList(it) => {
161 let indent = IndentLevel::from_node(it.syntax()); 161 let indent = IndentLevel::from_node(&it);
162 leading_ws = format!("\n{}", indent + 1); 162 leading_ws = format!("\n{}", indent + 1);
163 fn_def = fn_def.indent(indent + 1); 163 fn_def = fn_def.indent(indent + 1);
164 trailing_ws = format!("\n{}", indent); 164 trailing_ws = format!("\n{}", indent);
165 it.syntax().text_range().start() + TextSize::of('{') 165 it.text_range().start() + TextSize::of('{')
166 } 166 }
167 }; 167 };
168 168
@@ -179,14 +179,14 @@ impl FunctionBuilder {
179 179
180enum GeneratedFunctionTarget { 180enum GeneratedFunctionTarget {
181 BehindItem(SyntaxNode), 181 BehindItem(SyntaxNode),
182 InEmptyItemList(ast::ItemList), 182 InEmptyItemList(SyntaxNode),
183} 183}
184 184
185impl GeneratedFunctionTarget { 185impl GeneratedFunctionTarget {
186 fn syntax(&self) -> &SyntaxNode { 186 fn syntax(&self) -> &SyntaxNode {
187 match self { 187 match self {
188 GeneratedFunctionTarget::BehindItem(it) => it, 188 GeneratedFunctionTarget::BehindItem(it) => it,
189 GeneratedFunctionTarget::InEmptyItemList(it) => it.syntax(), 189 GeneratedFunctionTarget::InEmptyItemList(it) => it,
190 } 190 }
191 } 191 }
192} 192}
@@ -323,7 +323,16 @@ fn next_space_for_fn_in_module(
323 if let Some(last_item) = it.item_list().and_then(|it| it.items().last()) { 323 if let Some(last_item) = it.item_list().and_then(|it| it.items().last()) {
324 GeneratedFunctionTarget::BehindItem(last_item.syntax().clone()) 324 GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())
325 } else { 325 } else {
326 GeneratedFunctionTarget::InEmptyItemList(it.item_list()?) 326 GeneratedFunctionTarget::InEmptyItemList(it.item_list()?.syntax().clone())
327 }
328 }
329 hir::ModuleSource::BlockExpr(it) => {
330 if let Some(last_item) =
331 it.statements().take_while(|stmt| matches!(stmt, ast::Stmt::Item(_))).last()
332 {
333 GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())
334 } else {
335 GeneratedFunctionTarget::InEmptyItemList(it.syntax().clone())
327 } 336 }
328 } 337 }
329 }; 338 };
diff --git a/crates/assists/src/handlers/generate_impl.rs b/crates/assists/src/handlers/generate_impl.rs
index 9af45192b..827477272 100644
--- a/crates/assists/src/handlers/generate_impl.rs
+++ b/crates/assists/src/handlers/generate_impl.rs
@@ -1,6 +1,9 @@
1use itertools::Itertools; 1use itertools::Itertools;
2use stdx::format_to; 2use stdx::format_to;
3use syntax::ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner}; 3use syntax::{
4 ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner},
5 SmolStr,
6};
4 7
5use crate::{AssistContext, AssistId, AssistKind, Assists}; 8use crate::{AssistContext, AssistId, AssistKind, Assists};
6 9
@@ -49,16 +52,16 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()
49 format_to!(buf, "{}", type_params.syntax()); 52 format_to!(buf, "{}", type_params.syntax());
50 } 53 }
51 buf.push_str(" "); 54 buf.push_str(" ");
52 buf.push_str(name.text().as_str()); 55 buf.push_str(name.text());
53 if let Some(type_params) = type_params { 56 if let Some(type_params) = type_params {
54 let lifetime_params = type_params 57 let lifetime_params = type_params
55 .lifetime_params() 58 .lifetime_params()
56 .filter_map(|it| it.lifetime()) 59 .filter_map(|it| it.lifetime())
57 .map(|it| it.text().clone()); 60 .map(|it| SmolStr::from(it.text()));
58 let type_params = type_params 61 let type_params = type_params
59 .type_params() 62 .type_params()
60 .filter_map(|it| it.name()) 63 .filter_map(|it| it.name())
61 .map(|it| it.text().clone()); 64 .map(|it| SmolStr::from(it.text()));
62 65
63 let generic_params = lifetime_params.chain(type_params).format(", "); 66 let generic_params = lifetime_params.chain(type_params).format(", ");
64 format_to!(buf, "<{}>", generic_params) 67 format_to!(buf, "<{}>", generic_params)
diff --git a/crates/assists/src/handlers/generate_new.rs b/crates/assists/src/handlers/generate_new.rs
index 5c52b2bc8..b7390855a 100644
--- a/crates/assists/src/handlers/generate_new.rs
+++ b/crates/assists/src/handlers/generate_new.rs
@@ -3,7 +3,7 @@ use itertools::Itertools;
3use stdx::format_to; 3use stdx::format_to;
4use syntax::{ 4use syntax::{
5 ast::{self, AstNode, GenericParamsOwner, NameOwner, StructKind, VisibilityOwner}, 5 ast::{self, AstNode, GenericParamsOwner, NameOwner, StructKind, VisibilityOwner},
6 T, 6 SmolStr, T,
7}; 7};
8 8
9use crate::{AssistContext, AssistId, AssistKind, Assists}; 9use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -95,14 +95,14 @@ fn generate_impl_text(strukt: &ast::Struct, code: &str) -> String {
95 format_to!(buf, "{}", type_params.syntax()); 95 format_to!(buf, "{}", type_params.syntax());
96 } 96 }
97 buf.push_str(" "); 97 buf.push_str(" ");
98 buf.push_str(strukt.name().unwrap().text().as_str()); 98 buf.push_str(strukt.name().unwrap().text());
99 if let Some(type_params) = type_params { 99 if let Some(type_params) = type_params {
100 let lifetime_params = type_params 100 let lifetime_params = type_params
101 .lifetime_params() 101 .lifetime_params()
102 .filter_map(|it| it.lifetime()) 102 .filter_map(|it| it.lifetime())
103 .map(|it| it.text().clone()); 103 .map(|it| SmolStr::from(it.text()));
104 let type_params = 104 let type_params =
105 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); 105 type_params.type_params().filter_map(|it| it.name()).map(|it| SmolStr::from(it.text()));
106 format_to!(buf, "<{}>", lifetime_params.chain(type_params).format(", ")) 106 format_to!(buf, "<{}>", lifetime_params.chain(type_params).format(", "))
107 } 107 }
108 108
diff --git a/crates/assists/src/handlers/introduce_named_lifetime.rs b/crates/assists/src/handlers/introduce_named_lifetime.rs
index 3f5f44d69..02782eb6d 100644
--- a/crates/assists/src/handlers/introduce_named_lifetime.rs
+++ b/crates/assists/src/handlers/introduce_named_lifetime.rs
@@ -61,7 +61,7 @@ fn generate_fn_def_assist(
61 // compute the location which implicitly has the same lifetime as the anonymous lifetime 61 // compute the location which implicitly has the same lifetime as the anonymous lifetime
62 let loc_needing_lifetime = if let Some(self_param) = self_param { 62 let loc_needing_lifetime = if let Some(self_param) = self_param {
63 // if we have a self reference, use that 63 // if we have a self reference, use that
64 Some(self_param.self_token()?.text_range().start()) 64 Some(self_param.name()?.syntax().text_range().start())
65 } else { 65 } else {
66 // otherwise, if there's a single reference parameter without a named liftime, use that 66 // otherwise, if there's a single reference parameter without a named liftime, use that
67 let fn_params_without_lifetime: Vec<_> = param_list 67 let fn_params_without_lifetime: Vec<_> = param_list
diff --git a/crates/assists/src/handlers/qualify_path.rs b/crates/assists/src/handlers/qualify_path.rs
index a7d9fd4dc..b0b0d31b4 100644
--- a/crates/assists/src/handlers/qualify_path.rs
+++ b/crates/assists/src/handlers/qualify_path.rs
@@ -1,10 +1,7 @@
1use std::iter; 1use std::iter;
2 2
3use hir::AsName; 3use hir::{AsAssocItem, AsName};
4use ide_db::helpers::{ 4use ide_db::helpers::{import_assets::ImportCandidate, mod_path_to_ast};
5 import_assets::{ImportAssets, ImportCandidate},
6 mod_path_to_ast,
7};
8use ide_db::RootDatabase; 5use ide_db::RootDatabase;
9use syntax::{ 6use syntax::{
10 ast, 7 ast,
@@ -18,6 +15,8 @@ use crate::{
18 AssistId, AssistKind, GroupLabel, 15 AssistId, AssistKind, GroupLabel,
19}; 16};
20 17
18use super::auto_import::find_importable_node;
19
21// Assist: qualify_path 20// Assist: qualify_path
22// 21//
23// If the name is unresolved, provides all possible qualified paths for it. 22// If the name is unresolved, provides all possible qualified paths for it.
@@ -36,47 +35,38 @@ use crate::{
36// # pub mod std { pub mod collections { pub struct HashMap { } } } 35// # pub mod std { pub mod collections { pub struct HashMap { } } }
37// ``` 36// ```
38pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 37pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
39 let import_assets = 38 let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
40 if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
41 ImportAssets::for_regular_path(path_under_caret, &ctx.sema)
42 } else if let Some(method_under_caret) =
43 ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>()
44 {
45 ImportAssets::for_method_call(method_under_caret, &ctx.sema)
46 } else {
47 None
48 }?;
49 let proposed_imports = import_assets.search_for_relative_paths(&ctx.sema); 39 let proposed_imports = import_assets.search_for_relative_paths(&ctx.sema);
50 if proposed_imports.is_empty() { 40 if proposed_imports.is_empty() {
51 return None; 41 return None;
52 } 42 }
53 43
54 let candidate = import_assets.import_candidate(); 44 let candidate = import_assets.import_candidate();
55 let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; 45 let range = ctx.sema.original_range(&syntax_under_caret).range;
56 46
57 let qualify_candidate = match candidate { 47 let qualify_candidate = match candidate {
58 ImportCandidate::Path(candidate) => { 48 ImportCandidate::Path(candidate) => {
59 if candidate.qualifier.is_some() { 49 if candidate.qualifier.is_some() {
60 mark::hit!(qualify_path_qualifier_start); 50 mark::hit!(qualify_path_qualifier_start);
61 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; 51 let path = ast::Path::cast(syntax_under_caret)?;
62 let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); 52 let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?);
63 QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) 53 QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list())
64 } else { 54 } else {
65 mark::hit!(qualify_path_unqualified_name); 55 mark::hit!(qualify_path_unqualified_name);
66 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; 56 let path = ast::Path::cast(syntax_under_caret)?;
67 let generics = path.segment()?.generic_arg_list(); 57 let generics = path.segment()?.generic_arg_list();
68 QualifyCandidate::UnqualifiedName(generics) 58 QualifyCandidate::UnqualifiedName(generics)
69 } 59 }
70 } 60 }
71 ImportCandidate::TraitAssocItem(_) => { 61 ImportCandidate::TraitAssocItem(_) => {
72 mark::hit!(qualify_path_trait_assoc_item); 62 mark::hit!(qualify_path_trait_assoc_item);
73 let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; 63 let path = ast::Path::cast(syntax_under_caret)?;
74 let (qualifier, segment) = (path.qualifier()?, path.segment()?); 64 let (qualifier, segment) = (path.qualifier()?, path.segment()?);
75 QualifyCandidate::TraitAssocItem(qualifier, segment) 65 QualifyCandidate::TraitAssocItem(qualifier, segment)
76 } 66 }
77 ImportCandidate::TraitMethod(_) => { 67 ImportCandidate::TraitMethod(_) => {
78 mark::hit!(qualify_path_trait_method); 68 mark::hit!(qualify_path_trait_method);
79 let mcall_expr = ast::MethodCallExpr::cast(import_assets.syntax_under_caret().clone())?; 69 let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret)?;
80 QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr) 70 QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr)
81 } 71 }
82 }; 72 };
@@ -140,7 +130,7 @@ impl QualifyCandidate<'_> {
140 let generics = 130 let generics =
141 mcall_expr.generic_arg_list().as_ref().map_or_else(String::new, ToString::to_string); 131 mcall_expr.generic_arg_list().as_ref().map_or_else(String::new, ToString::to_string);
142 let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args()); 132 let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args());
143 let trait_ = item_as_trait(item)?; 133 let trait_ = item_as_trait(db, item)?;
144 let method = find_trait_method(db, trait_, &trait_method_name)?; 134 let method = find_trait_method(db, trait_, &trait_method_name)?;
145 if let Some(self_access) = method.self_param(db).map(|sp| sp.access(db)) { 135 if let Some(self_access) = method.self_param(db).map(|sp| sp.access(db)) {
146 let receiver = match self_access { 136 let receiver = match self_access {
@@ -179,11 +169,13 @@ fn find_trait_method(
179 } 169 }
180} 170}
181 171
182fn item_as_trait(item: hir::ItemInNs) -> Option<hir::Trait> { 172fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> {
183 if let hir::ModuleDef::Trait(trait_) = hir::ModuleDef::from(item.as_module_def_id()?) { 173 let item_module_def = hir::ModuleDef::from(item.as_module_def_id()?);
174
175 if let hir::ModuleDef::Trait(trait_) = item_module_def {
184 Some(trait_) 176 Some(trait_)
185 } else { 177 } else {
186 None 178 item_module_def.as_assoc_item(db)?.containing_trait(db)
187 } 179 }
188} 180}
189 181
@@ -191,7 +183,8 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel {
191 let name = match candidate { 183 let name = match candidate {
192 ImportCandidate::Path(it) => &it.name, 184 ImportCandidate::Path(it) => &it.name,
193 ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name, 185 ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name,
194 }; 186 }
187 .text();
195 GroupLabel(format!("Qualify {}", name)) 188 GroupLabel(format!("Qualify {}", name))
196} 189}
197 190
diff --git a/crates/assists/src/handlers/raw_string.rs b/crates/assists/src/handlers/raw_string.rs
index be963f162..d95267607 100644
--- a/crates/assists/src/handlers/raw_string.rs
+++ b/crates/assists/src/handlers/raw_string.rs
@@ -138,7 +138,7 @@ pub(crate) fn remove_hash(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
138 return None; 138 return None;
139 } 139 }
140 140
141 let text = token.text().as_str(); 141 let text = token.text();
142 if !text.starts_with("r#") && text.ends_with('#') { 142 if !text.starts_with("r#") && text.ends_with('#') {
143 return None; 143 return None;
144 } 144 }
diff --git a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs
index bd4c1c806..6aa9d2f2c 100644
--- a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -3,7 +3,7 @@ use ide_db::imports_locator;
3use itertools::Itertools; 3use itertools::Itertools;
4use syntax::{ 4use syntax::{
5 ast::{self, make, AstNode}, 5 ast::{self, make, AstNode},
6 Direction, SmolStr, 6 Direction,
7 SyntaxKind::{IDENT, WHITESPACE}, 7 SyntaxKind::{IDENT, WHITESPACE},
8 TextSize, 8 TextSize,
9}; 9};
@@ -43,17 +43,18 @@ pub(crate) fn replace_derive_with_manual_impl(
43) -> Option<()> { 43) -> Option<()> {
44 let attr = ctx.find_node_at_offset::<ast::Attr>()?; 44 let attr = ctx.find_node_at_offset::<ast::Attr>()?;
45 45
46 let attr_name = attr 46 let has_derive = attr
47 .syntax() 47 .syntax()
48 .descendants_with_tokens() 48 .descendants_with_tokens()
49 .filter(|t| t.kind() == IDENT) 49 .filter(|t| t.kind() == IDENT)
50 .find_map(syntax::NodeOrToken::into_token) 50 .find_map(syntax::NodeOrToken::into_token)
51 .filter(|t| t.text() == "derive")? 51 .filter(|t| t.text() == "derive")
52 .text() 52 .is_some();
53 .clone(); 53 if !has_derive {
54 return None;
55 }
54 56
55 let trait_token = 57 let trait_token = ctx.token_at_offset().find(|t| t.kind() == IDENT && t.text() != "derive")?;
56 ctx.token_at_offset().find(|t| t.kind() == IDENT && *t.text() != attr_name)?;
57 let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text()))); 58 let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text())));
58 59
59 let annotated_name = attr.syntax().siblings(Direction::Next).find_map(ast::Name::cast)?; 60 let annotated_name = attr.syntax().siblings(Direction::Next).find_map(ast::Name::cast)?;
@@ -176,9 +177,9 @@ fn update_attribute(
176 .syntax() 177 .syntax()
177 .descendants_with_tokens() 178 .descendants_with_tokens()
178 .filter(|t| t.kind() == IDENT) 179 .filter(|t| t.kind() == IDENT)
179 .filter_map(|t| t.into_token().map(|t| t.text().clone())) 180 .filter_map(|t| t.into_token().map(|t| t.text().to_string()))
180 .filter(|t| t != trait_name.text()) 181 .filter(|t| t != trait_name.text())
181 .collect::<Vec<SmolStr>>(); 182 .collect::<Vec<_>>();
182 let has_more_derives = !new_attr_input.is_empty(); 183 let has_more_derives = !new_attr_input.is_empty();
183 184
184 if has_more_derives { 185 if has_more_derives {
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index fc9f83bab..44c35bafa 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -223,7 +223,7 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
223 let method = mce.name_ref()?; 223 let method = mce.name_ref()?;
224 let arg_list = mce.arg_list()?; 224 let arg_list = mce.arg_list()?;
225 225
226 let method = match method.text().as_str() { 226 let method = match method.text() {
227 "is_some" => "is_none", 227 "is_some" => "is_none",
228 "is_none" => "is_some", 228 "is_none" => "is_some",
229 "is_ok" => "is_err", 229 "is_ok" => "is_err",
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 2dd8fbe67..b5f7e4200 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -178,7 +178,7 @@ pub struct CrateData {
178 pub root_file_id: FileId, 178 pub root_file_id: FileId,
179 pub edition: Edition, 179 pub edition: Edition,
180 /// A name used in the package's project declaration: for Cargo projects, 180 /// A name used in the package's project declaration: for Cargo projects,
181 /// it's [package].name, can be different for other project types or even 181 /// its `[package].name` can be different for other project types or even
182 /// absent (a dummy crate for the code snippet, for example). 182 /// absent (a dummy crate for the code snippet, for example).
183 /// 183 ///
184 /// For purposes of analysis, crates are anonymous (only names in 184 /// For purposes of analysis, crates are anonymous (only names in
diff --git a/crates/completion/src/completions/attribute.rs b/crates/completion/src/completions/attribute.rs
index e5522980d..ab25a8c58 100644
--- a/crates/completion/src/completions/attribute.rs
+++ b/crates/completion/src/completions/attribute.rs
@@ -99,13 +99,14 @@ const ATTRIBUTES: &[AttrCompletion] = &[
99 Some("export_name"), 99 Some("export_name"),
100 Some(r#"export_name = "${0:exported_symbol_name}""#), 100 Some(r#"export_name = "${0:exported_symbol_name}""#),
101 ), 101 ),
102 attr(r#"doc(alias = "…")"#, Some("docalias"), Some(r#"doc(alias = "${0:docs}")"#)),
102 attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)), 103 attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
103 attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(), 104 attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(),
104 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")), 105 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")),
105 // FIXME: resolve through macro resolution? 106 // FIXME: resolve through macro resolution?
106 attr("global_allocator", None, None).prefer_inner(), 107 attr("global_allocator", None, None).prefer_inner(),
107 attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)), 108 attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)),
108 attr("inline(…)", Some("inline"), Some("inline(${0:lint})")), 109 attr("inline", Some("inline"), Some("inline")),
109 attr("link", None, None), 110 attr("link", None, None),
110 attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)), 111 attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)),
111 attr( 112 attr(
@@ -468,10 +469,11 @@ struct Test {}
468 at deprecated 469 at deprecated
469 at derive(…) 470 at derive(…)
470 at export_name = "…" 471 at export_name = "…"
472 at doc(alias = "…")
471 at doc = "…" 473 at doc = "…"
472 at forbid(…) 474 at forbid(…)
473 at ignore = "…" 475 at ignore = "…"
474 at inline(…) 476 at inline
475 at link 477 at link
476 at link_name = "…" 478 at link_name = "…"
477 at link_section = "…" 479 at link_section = "…"
@@ -515,12 +517,13 @@ struct Test {}
515 at deprecated 517 at deprecated
516 at derive(…) 518 at derive(…)
517 at export_name = "…" 519 at export_name = "…"
520 at doc(alias = "…")
518 at doc = "…" 521 at doc = "…"
519 at feature(…) 522 at feature(…)
520 at forbid(…) 523 at forbid(…)
521 at global_allocator 524 at global_allocator
522 at ignore = "…" 525 at ignore = "…"
523 at inline(…) 526 at inline
524 at link 527 at link
525 at link_name = "…" 528 at link_name = "…"
526 at link_section = "…" 529 at link_section = "…"
diff --git a/crates/completion/src/completions/flyimport.rs b/crates/completion/src/completions/flyimport.rs
index 222809638..dc0b38a16 100644
--- a/crates/completion/src/completions/flyimport.rs
+++ b/crates/completion/src/completions/flyimport.rs
@@ -20,11 +20,14 @@
20//! # pub mod std { pub mod marker { pub struct PhantomData { } } } 20//! # pub mod std { pub mod marker { pub struct PhantomData { } } }
21//! ``` 21//! ```
22//! 22//!
23//! Also completes associated items, that require trait imports.
24//!
23//! .Fuzzy search details 25//! .Fuzzy search details
24//! 26//!
25//! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only 27//! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
26//! (i.e. in `HashMap` in the `std::collections::HashMap` path). 28//! (i.e. in `HashMap` in the `std::collections::HashMap` path).
27//! For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols. 29//! For the same reasons, avoids searching for any path imports for inputs with their length less that 2 symbols
30//! (but shows all associated items for any input length).
28//! 31//!
29//! .Import configuration 32//! .Import configuration
30//! 33//!
@@ -45,10 +48,12 @@
45//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding 48//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding
46//! capability enabled. 49//! capability enabled.
47 50
48use either::Either; 51use hir::{AsAssocItem, ModPath, ScopeDef};
49use hir::{ModPath, ScopeDef}; 52use ide_db::helpers::{
50use ide_db::{helpers::insert_use::ImportScope, imports_locator}; 53 import_assets::{ImportAssets, ImportCandidate},
51use syntax::AstNode; 54 insert_use::ImportScope,
55};
56use syntax::{AstNode, SyntaxNode, T};
52use test_utils::mark; 57use test_utils::mark;
53 58
54use crate::{ 59use crate::{
@@ -60,58 +65,108 @@ use crate::{
60use super::Completions; 65use super::Completions;
61 66
62pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 67pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
63 if !ctx.config.enable_autoimport_completions { 68 if !ctx.config.enable_imports_on_the_fly {
64 return None; 69 return None;
65 } 70 }
66 if ctx.attribute_under_caret.is_some() || ctx.mod_declaration_under_caret.is_some() { 71 if ctx.attribute_under_caret.is_some() || ctx.mod_declaration_under_caret.is_some() {
67 return None; 72 return None;
68 } 73 }
69 let potential_import_name = ctx.token.to_string(); 74 let potential_import_name = {
70 if potential_import_name.len() < 2 { 75 let token_kind = ctx.token.kind();
71 return None; 76 if matches!(token_kind, T![.] | T![::]) {
72 } 77 String::new()
73 let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string()); 78 } else {
79 ctx.token.to_string()
80 }
81 };
74 82
75 let current_module = ctx.scope.module()?; 83 let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string());
76 let anchor = ctx.name_ref_syntax.as_ref()?;
77 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
78 84
79 let user_input_lowercased = potential_import_name.to_lowercase(); 85 let user_input_lowercased = potential_import_name.to_lowercase();
80 let mut all_mod_paths = imports_locator::find_similar_imports( 86 let import_assets = import_assets(ctx, potential_import_name)?;
87 let import_scope = ImportScope::find_insert_use_container(
88 position_for_import(ctx, Some(import_assets.import_candidate()))?,
81 &ctx.sema, 89 &ctx.sema,
82 ctx.krate?, 90 )?;
83 Some(40), 91 let mut all_mod_paths = import_assets
84 potential_import_name, 92 .search_for_relative_paths(&ctx.sema)
85 true, 93 .into_iter()
86 true, 94 .map(|(mod_path, item_in_ns)| {
87 ) 95 let scope_item = match item_in_ns {
88 .filter_map(|import_candidate| { 96 hir::ItemInNs::Types(id) => ScopeDef::ModuleDef(id.into()),
89 Some(match import_candidate { 97 hir::ItemInNs::Values(id) => ScopeDef::ModuleDef(id.into()),
90 Either::Left(module_def) => { 98 hir::ItemInNs::Macros(id) => ScopeDef::MacroDef(id.into()),
91 (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def)) 99 };
92 } 100 (mod_path, scope_item)
93 Either::Right(macro_def) => {
94 (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def))
95 }
96 }) 101 })
97 }) 102 .collect::<Vec<_>>();
98 .filter(|(mod_path, _)| mod_path.len() > 1)
99 .collect::<Vec<_>>();
100
101 all_mod_paths.sort_by_cached_key(|(mod_path, _)| { 103 all_mod_paths.sort_by_cached_key(|(mod_path, _)| {
102 compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) 104 compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased)
103 }); 105 });
104 106
105 acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| { 107 acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| {
106 render_resolution_with_import( 108 let import_for_trait_assoc_item = match definition {
107 RenderContext::new(ctx), 109 ScopeDef::ModuleDef(module_def) => module_def
108 ImportEdit { import_path, import_scope: import_scope.clone() }, 110 .as_assoc_item(ctx.db)
109 &definition, 111 .and_then(|assoc| assoc.containing_trait(ctx.db))
110 ) 112 .is_some(),
113 _ => false,
114 };
115 let import_edit = ImportEdit {
116 import_path,
117 import_scope: import_scope.clone(),
118 import_for_trait_assoc_item,
119 };
120 render_resolution_with_import(RenderContext::new(ctx), import_edit, &definition)
111 })); 121 }));
112 Some(()) 122 Some(())
113} 123}
114 124
125pub(crate) fn position_for_import<'a>(
126 ctx: &'a CompletionContext,
127 import_candidate: Option<&ImportCandidate>,
128) -> Option<&'a SyntaxNode> {
129 Some(match import_candidate {
130 Some(ImportCandidate::Path(_)) => ctx.name_ref_syntax.as_ref()?.syntax(),
131 Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual.as_ref()?.syntax(),
132 Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver.as_ref()?.syntax(),
133 None => ctx
134 .name_ref_syntax
135 .as_ref()
136 .map(|name_ref| name_ref.syntax())
137 .or_else(|| ctx.path_qual.as_ref().map(|path| path.syntax()))
138 .or_else(|| ctx.dot_receiver.as_ref().map(|expr| expr.syntax()))?,
139 })
140}
141
142fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> {
143 let current_module = ctx.scope.module()?;
144 if let Some(dot_receiver) = &ctx.dot_receiver {
145 ImportAssets::for_fuzzy_method_call(
146 current_module,
147 ctx.sema.type_of_expr(dot_receiver)?,
148 fuzzy_name,
149 )
150 } else {
151 let fuzzy_name_length = fuzzy_name.len();
152 let assets_for_path = ImportAssets::for_fuzzy_path(
153 current_module,
154 ctx.path_qual.clone(),
155 fuzzy_name,
156 &ctx.sema,
157 );
158
159 if matches!(assets_for_path.as_ref()?.import_candidate(), ImportCandidate::Path(_))
160 && fuzzy_name_length < 2
161 {
162 mark::hit!(ignore_short_input_for_path);
163 None
164 } else {
165 assets_for_path
166 }
167 }
168}
169
115fn compute_fuzzy_completion_order_key( 170fn compute_fuzzy_completion_order_key(
116 proposed_mod_path: &ModPath, 171 proposed_mod_path: &ModPath,
117 user_input_lowercased: &str, 172 user_input_lowercased: &str,
@@ -224,6 +279,30 @@ fn main() {
224 } 279 }
225 280
226 #[test] 281 #[test]
282 fn short_paths_are_ignored() {
283 mark::check!(ignore_short_input_for_path);
284
285 check(
286 r#"
287//- /lib.rs crate:dep
288pub struct FirstStruct;
289pub mod some_module {
290 pub struct SecondStruct;
291 pub struct ThirdStruct;
292}
293
294//- /main.rs crate:main deps:dep
295use dep::{FirstStruct, some_module::SecondStruct};
296
297fn main() {
298 t$0
299}
300"#,
301 expect![[r#""#]],
302 );
303 }
304
305 #[test]
227 fn fuzzy_completions_come_in_specific_order() { 306 fn fuzzy_completions_come_in_specific_order() {
228 mark::check!(certain_fuzzy_order_test); 307 mark::check!(certain_fuzzy_order_test);
229 check( 308 check(
@@ -259,6 +338,176 @@ fn main() {
259 } 338 }
260 339
261 #[test] 340 #[test]
341 fn trait_function_fuzzy_completion() {
342 let fixture = r#"
343 //- /lib.rs crate:dep
344 pub mod test_mod {
345 pub trait TestTrait {
346 const SPECIAL_CONST: u8;
347 type HumbleType;
348 fn weird_function();
349 fn random_method(&self);
350 }
351 pub struct TestStruct {}
352 impl TestTrait for TestStruct {
353 const SPECIAL_CONST: u8 = 42;
354 type HumbleType = ();
355 fn weird_function() {}
356 fn random_method(&self) {}
357 }
358 }
359
360 //- /main.rs crate:main deps:dep
361 fn main() {
362 dep::test_mod::TestStruct::wei$0
363 }
364 "#;
365
366 check(
367 fixture,
368 expect![[r#"
369 fn weird_function() (dep::test_mod::TestTrait) fn weird_function()
370 "#]],
371 );
372
373 check_edit(
374 "weird_function",
375 fixture,
376 r#"
377use dep::test_mod::TestTrait;
378
379fn main() {
380 dep::test_mod::TestStruct::weird_function()$0
381}
382"#,
383 );
384 }
385
386 #[test]
387 fn trait_const_fuzzy_completion() {
388 let fixture = r#"
389 //- /lib.rs crate:dep
390 pub mod test_mod {
391 pub trait TestTrait {
392 const SPECIAL_CONST: u8;
393 type HumbleType;
394 fn weird_function();
395 fn random_method(&self);
396 }
397 pub struct TestStruct {}
398 impl TestTrait for TestStruct {
399 const SPECIAL_CONST: u8 = 42;
400 type HumbleType = ();
401 fn weird_function() {}
402 fn random_method(&self) {}
403 }
404 }
405
406 //- /main.rs crate:main deps:dep
407 fn main() {
408 dep::test_mod::TestStruct::spe$0
409 }
410 "#;
411
412 check(
413 fixture,
414 expect![[r#"
415 ct SPECIAL_CONST (dep::test_mod::TestTrait)
416 "#]],
417 );
418
419 check_edit(
420 "SPECIAL_CONST",
421 fixture,
422 r#"
423use dep::test_mod::TestTrait;
424
425fn main() {
426 dep::test_mod::TestStruct::SPECIAL_CONST
427}
428"#,
429 );
430 }
431
432 #[test]
433 fn trait_method_fuzzy_completion() {
434 let fixture = r#"
435 //- /lib.rs crate:dep
436 pub mod test_mod {
437 pub trait TestTrait {
438 const SPECIAL_CONST: u8;
439 type HumbleType;
440 fn weird_function();
441 fn random_method(&self);
442 }
443 pub struct TestStruct {}
444 impl TestTrait for TestStruct {
445 const SPECIAL_CONST: u8 = 42;
446 type HumbleType = ();
447 fn weird_function() {}
448 fn random_method(&self) {}
449 }
450 }
451
452 //- /main.rs crate:main deps:dep
453 fn main() {
454 let test_struct = dep::test_mod::TestStruct {};
455 test_struct.ran$0
456 }
457 "#;
458
459 check(
460 fixture,
461 expect![[r#"
462 me random_method() (dep::test_mod::TestTrait) fn random_method(&self)
463 "#]],
464 );
465
466 check_edit(
467 "random_method",
468 fixture,
469 r#"
470use dep::test_mod::TestTrait;
471
472fn main() {
473 let test_struct = dep::test_mod::TestStruct {};
474 test_struct.random_method()$0
475}
476"#,
477 );
478 }
479
480 #[test]
481 fn no_trait_type_fuzzy_completion() {
482 check(
483 r#"
484//- /lib.rs crate:dep
485pub mod test_mod {
486 pub trait TestTrait {
487 const SPECIAL_CONST: u8;
488 type HumbleType;
489 fn weird_function();
490 fn random_method(&self);
491 }
492 pub struct TestStruct {}
493 impl TestTrait for TestStruct {
494 const SPECIAL_CONST: u8 = 42;
495 type HumbleType = ();
496 fn weird_function() {}
497 fn random_method(&self) {}
498 }
499}
500
501//- /main.rs crate:main deps:dep
502fn main() {
503 dep::test_mod::TestStruct::hum$0
504}
505"#,
506 expect![[r#""#]],
507 );
508 }
509
510 #[test]
262 fn does_not_propose_names_in_scope() { 511 fn does_not_propose_names_in_scope() {
263 check( 512 check(
264 r#" 513 r#"
@@ -288,4 +537,131 @@ fn main() {
288 expect![[r#""#]], 537 expect![[r#""#]],
289 ); 538 );
290 } 539 }
540
541 #[test]
542 fn does_not_propose_traits_in_scope() {
543 check(
544 r#"
545//- /lib.rs crate:dep
546pub mod test_mod {
547 pub trait TestTrait {
548 const SPECIAL_CONST: u8;
549 type HumbleType;
550 fn weird_function();
551 fn random_method(&self);
552 }
553 pub struct TestStruct {}
554 impl TestTrait for TestStruct {
555 const SPECIAL_CONST: u8 = 42;
556 type HumbleType = ();
557 fn weird_function() {}
558 fn random_method(&self) {}
559 }
560}
561
562//- /main.rs crate:main deps:dep
563use dep::test_mod::{TestStruct, TestTrait};
564fn main() {
565 dep::test_mod::TestStruct::hum$0
566}
567"#,
568 expect![[r#""#]],
569 );
570 }
571
572 #[test]
573 fn blanket_trait_impl_import() {
574 check_edit(
575 "another_function",
576 r#"
577//- /lib.rs crate:dep
578pub mod test_mod {
579 pub struct TestStruct {}
580 pub trait TestTrait {
581 fn another_function();
582 }
583 impl<T> TestTrait for T {
584 fn another_function() {}
585 }
586}
587
588//- /main.rs crate:main deps:dep
589fn main() {
590 dep::test_mod::TestStruct::ano$0
591}
592"#,
593 r#"
594use dep::test_mod::TestTrait;
595
596fn main() {
597 dep::test_mod::TestStruct::another_function()$0
598}
599"#,
600 );
601 }
602
603 #[test]
604 fn zero_input_deprecated_assoc_item_completion() {
605 check(
606 r#"
607//- /lib.rs crate:dep
608pub mod test_mod {
609 #[deprecated]
610 pub trait TestTrait {
611 const SPECIAL_CONST: u8;
612 type HumbleType;
613 fn weird_function();
614 fn random_method(&self);
615 }
616 pub struct TestStruct {}
617 impl TestTrait for TestStruct {
618 const SPECIAL_CONST: u8 = 42;
619 type HumbleType = ();
620 fn weird_function() {}
621 fn random_method(&self) {}
622 }
623}
624
625//- /main.rs crate:main deps:dep
626fn main() {
627 let test_struct = dep::test_mod::TestStruct {};
628 test_struct.$0
629}
630 "#,
631 expect![[r#"
632 me random_method() (dep::test_mod::TestTrait) fn random_method(&self) DEPRECATED
633 "#]],
634 );
635
636 check(
637 r#"
638//- /lib.rs crate:dep
639pub mod test_mod {
640 #[deprecated]
641 pub trait TestTrait {
642 const SPECIAL_CONST: u8;
643 type HumbleType;
644 fn weird_function();
645 fn random_method(&self);
646 }
647 pub struct TestStruct {}
648 impl TestTrait for TestStruct {
649 const SPECIAL_CONST: u8 = 42;
650 type HumbleType = ();
651 fn weird_function() {}
652 fn random_method(&self) {}
653 }
654}
655
656//- /main.rs crate:main deps:dep
657fn main() {
658 dep::test_mod::TestStruct::$0
659}
660"#,
661 expect![[r#"
662 ct SPECIAL_CONST (dep::test_mod::TestTrait) DEPRECATED
663 fn weird_function() (dep::test_mod::TestTrait) fn weird_function() DEPRECATED
664 "#]],
665 );
666 }
291} 667}
diff --git a/crates/completion/src/completions/fn_param.rs b/crates/completion/src/completions/fn_param.rs
index 5505c3559..38e33a93e 100644
--- a/crates/completion/src/completions/fn_param.rs
+++ b/crates/completion/src/completions/fn_param.rs
@@ -6,7 +6,7 @@ use syntax::{
6 match_ast, AstNode, 6 match_ast, AstNode,
7}; 7};
8 8
9use crate::{CompletionContext, CompletionItem, CompletionKind, Completions}; 9use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
10 10
11/// Complete repeated parameters, both name and type. For example, if all 11/// Complete repeated parameters, both name and type. For example, if all
12/// functions in a file have a `spam: &mut Spam` parameter, a completion with 12/// functions in a file have a `spam: &mut Spam` parameter, a completion with
@@ -58,7 +58,7 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
58 }) 58 })
59 .for_each(|(label, lookup)| { 59 .for_each(|(label, lookup)| {
60 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label) 60 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label)
61 .kind(crate::CompletionItemKind::Binding) 61 .kind(CompletionItemKind::Binding)
62 .lookup_by(lookup) 62 .lookup_by(lookup)
63 .add_to(acc) 63 .add_to(acc)
64 }); 64 });
diff --git a/crates/completion/src/completions/mod_.rs b/crates/completion/src/completions/mod_.rs
index 00e951ca9..352fc7c77 100644
--- a/crates/completion/src/completions/mod_.rs
+++ b/crates/completion/src/completions/mod_.rs
@@ -3,11 +3,13 @@
3use std::iter; 3use std::iter;
4 4
5use hir::{Module, ModuleSource}; 5use hir::{Module, ModuleSource};
6use ide_db::base_db::{SourceDatabaseExt, VfsPath}; 6use ide_db::{
7use ide_db::RootDatabase; 7 base_db::{SourceDatabaseExt, VfsPath},
8 RootDatabase, SymbolKind,
9};
8use rustc_hash::FxHashSet; 10use rustc_hash::FxHashSet;
9 11
10use crate::{CompletionItem, CompletionItemKind}; 12use crate::CompletionItem;
11 13
12use crate::{context::CompletionContext, item::CompletionKind, Completions}; 14use crate::{context::CompletionContext, item::CompletionKind, Completions};
13 15
@@ -79,7 +81,7 @@ pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Op
79 label.push(';'); 81 label.push(';');
80 } 82 }
81 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), &label) 83 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), &label)
82 .kind(CompletionItemKind::Module) 84 .kind(SymbolKind::Module)
83 .add_to(acc) 85 .add_to(acc)
84 }); 86 });
85 87
diff --git a/crates/completion/src/completions/record.rs b/crates/completion/src/completions/record.rs
index bb6354ded..0a7927eb8 100644
--- a/crates/completion/src/completions/record.rs
+++ b/crates/completion/src/completions/record.rs
@@ -1,10 +1,8 @@
1//! Complete fields in record literals and patterns. 1//! Complete fields in record literals and patterns.
2use ide_db::helpers::FamousDefs; 2use ide_db::{helpers::FamousDefs, SymbolKind};
3use syntax::ast::Expr; 3use syntax::ast::Expr;
4 4
5use crate::{ 5use crate::{item::CompletionKind, CompletionContext, CompletionItem, Completions};
6 item::CompletionKind, CompletionContext, CompletionItem, CompletionItemKind, Completions,
7};
8 6
9pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 7pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
10 let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) { 8 let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) {
@@ -31,7 +29,7 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
31 "..Default::default()", 29 "..Default::default()",
32 ) 30 )
33 .insert_text(completion_text) 31 .insert_text(completion_text)
34 .kind(CompletionItemKind::Field) 32 .kind(SymbolKind::Field)
35 .build(), 33 .build(),
36 ); 34 );
37 } 35 }
diff --git a/crates/completion/src/completions/trait_impl.rs b/crates/completion/src/completions/trait_impl.rs
index 135ae49dc..f258ad9c3 100644
--- a/crates/completion/src/completions/trait_impl.rs
+++ b/crates/completion/src/completions/trait_impl.rs
@@ -32,7 +32,7 @@
32//! ``` 32//! ```
33 33
34use hir::{self, HasAttrs, HasSource}; 34use hir::{self, HasAttrs, HasSource};
35use ide_db::traits::get_missing_assoc_items; 35use ide_db::{traits::get_missing_assoc_items, SymbolKind};
36use syntax::{ 36use syntax::{
37 ast::{self, edit, Impl}, 37 ast::{self, edit, Impl},
38 display::function_declaration, 38 display::function_declaration,
@@ -152,7 +152,7 @@ fn add_function_impl(
152 let completion_kind = if func.self_param(ctx.db).is_some() { 152 let completion_kind = if func.self_param(ctx.db).is_some() {
153 CompletionItemKind::Method 153 CompletionItemKind::Method
154 } else { 154 } else {
155 CompletionItemKind::Function 155 CompletionItemKind::SymbolKind(SymbolKind::Function)
156 }; 156 };
157 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); 157 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());
158 158
@@ -188,7 +188,7 @@ fn add_type_alias_impl(
188 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) 188 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
189 .text_edit(TextEdit::replace(range, snippet)) 189 .text_edit(TextEdit::replace(range, snippet))
190 .lookup_by(alias_name) 190 .lookup_by(alias_name)
191 .kind(CompletionItemKind::TypeAlias) 191 .kind(SymbolKind::TypeAlias)
192 .set_documentation(type_alias.docs(ctx.db)) 192 .set_documentation(type_alias.docs(ctx.db))
193 .add_to(acc); 193 .add_to(acc);
194} 194}
@@ -211,7 +211,7 @@ fn add_const_impl(
211 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) 211 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
212 .text_edit(TextEdit::replace(range, snippet)) 212 .text_edit(TextEdit::replace(range, snippet))
213 .lookup_by(const_name) 213 .lookup_by(const_name)
214 .kind(CompletionItemKind::Const) 214 .kind(SymbolKind::Const)
215 .set_documentation(const_.docs(ctx.db)) 215 .set_documentation(const_.docs(ctx.db))
216 .add_to(acc); 216 .add_to(acc);
217 } 217 }
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index ac5596ca4..a289efc34 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -29,6 +29,10 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
29 } 29 }
30 30
31 ctx.scope.process_all_names(&mut |name, res| { 31 ctx.scope.process_all_names(&mut |name, res| {
32 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
33 mark::hit!(skip_lifetime_completion);
34 return;
35 }
32 if ctx.use_item_syntax.is_some() { 36 if ctx.use_item_syntax.is_some() {
33 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) { 37 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) {
34 if name_ref.syntax().text() == name.to_string().as_str() { 38 if name_ref.syntax().text() == name.to_string().as_str() {
@@ -37,7 +41,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
37 } 41 }
38 } 42 }
39 } 43 }
40 acc.add_resolution(ctx, name.to_string(), &res) 44 acc.add_resolution(ctx, name.to_string(), &res);
41 }); 45 });
42} 46}
43 47
@@ -161,8 +165,8 @@ fn quux(x: i32) {
161} 165}
162"#, 166"#,
163 expect![[r#" 167 expect![[r#"
164 bn y i32 168 lc y i32
165 bn x i32 169 lc x i32
166 fn quux(…) fn quux(x: i32) 170 fn quux(…) fn quux(x: i32)
167 "#]], 171 "#]],
168 ); 172 );
@@ -183,8 +187,8 @@ fn quux() {
183} 187}
184"#, 188"#,
185 expect![[r#" 189 expect![[r#"
186 bn b i32 190 lc b i32
187 bn a 191 lc a
188 fn quux() fn quux() 192 fn quux() fn quux()
189 "#]], 193 "#]],
190 ); 194 );
@@ -199,7 +203,7 @@ fn quux() {
199} 203}
200"#, 204"#,
201 expect![[r#" 205 expect![[r#"
202 bn x 206 lc x
203 fn quux() fn quux() 207 fn quux() fn quux()
204 "#]], 208 "#]],
205 ); 209 );
@@ -234,6 +238,24 @@ fn main() {
234 fn quux() fn quux<T>() 238 fn quux() fn quux<T>()
235 "#]], 239 "#]],
236 ); 240 );
241 check(
242 r#"fn quux<const C: usize>() { $0 }"#,
243 expect![[r#"
244 cp C
245 fn quux() fn quux<const C: usize>()
246 "#]],
247 );
248 }
249
250 #[test]
251 fn does_not_complete_lifetimes() {
252 mark::check!(skip_lifetime_completion);
253 check(
254 r#"fn quux<'a>() { $0 }"#,
255 expect![[r#"
256 fn quux() fn quux<'a>()
257 "#]],
258 );
237 } 259 }
238 260
239 #[test] 261 #[test]
@@ -241,7 +263,7 @@ fn main() {
241 check( 263 check(
242 r#"struct S<T> { x: $0}"#, 264 r#"struct S<T> { x: $0}"#,
243 expect![[r#" 265 expect![[r#"
244 tp Self 266 sp Self
245 tp T 267 tp T
246 st S<…> 268 st S<…>
247 "#]], 269 "#]],
@@ -253,7 +275,7 @@ fn main() {
253 check( 275 check(
254 r#"enum X { Y($0) }"#, 276 r#"enum X { Y($0) }"#,
255 expect![[r#" 277 expect![[r#"
256 tp Self 278 sp Self
257 en X 279 en X
258 "#]], 280 "#]],
259 ); 281 );
@@ -356,8 +378,8 @@ fn foo() {
356"#, 378"#,
357 // FIXME: should be only one bar here 379 // FIXME: should be only one bar here
358 expect![[r#" 380 expect![[r#"
359 bn bar i32 381 lc bar i32
360 bn bar i32 382 lc bar i32
361 fn foo() fn foo() 383 fn foo() fn foo()
362 "#]], 384 "#]],
363 ); 385 );
@@ -368,8 +390,8 @@ fn foo() {
368 check( 390 check(
369 r#"impl S { fn foo(&self) { $0 } }"#, 391 r#"impl S { fn foo(&self) { $0 } }"#,
370 expect![[r#" 392 expect![[r#"
371 bn self &{unknown} 393 lc self &{unknown}
372 tp Self 394 sp Self
373 "#]], 395 "#]],
374 ); 396 );
375 } 397 }
@@ -553,8 +575,8 @@ fn quux(x: i32) {
553} 575}
554"#, 576"#,
555 expect![[r#" 577 expect![[r#"
556 bn y i32 578 lc y i32
557 bn x i32 579 lc x i32
558 fn quux(…) fn quux(x: i32) 580 fn quux(…) fn quux(x: i32)
559 ma m!(…) macro_rules! m 581 ma m!(…) macro_rules! m
560 "#]], 582 "#]],
@@ -572,8 +594,8 @@ fn quux(x: i32) {
572} 594}
573", 595",
574 expect![[r#" 596 expect![[r#"
575 bn y i32 597 lc y i32
576 bn x i32 598 lc x i32
577 fn quux(…) fn quux(x: i32) 599 fn quux(…) fn quux(x: i32)
578 ma m!(…) macro_rules! m 600 ma m!(…) macro_rules! m
579 "#]], 601 "#]],
@@ -591,8 +613,8 @@ fn quux(x: i32) {
591} 613}
592"#, 614"#,
593 expect![[r#" 615 expect![[r#"
594 bn y i32 616 lc y i32
595 bn x i32 617 lc x i32
596 fn quux(…) fn quux(x: i32) 618 fn quux(…) fn quux(x: i32)
597 ma m!(…) macro_rules! m 619 ma m!(…) macro_rules! m
598 "#]], 620 "#]],
@@ -728,7 +750,7 @@ struct MyStruct {}
728impl My$0 750impl My$0
729"#, 751"#,
730 expect![[r#" 752 expect![[r#"
731 tp Self 753 sp Self
732 tt MyTrait 754 tt MyTrait
733 st MyStruct 755 st MyStruct
734 "#]], 756 "#]],
diff --git a/crates/completion/src/config.rs b/crates/completion/src/config.rs
index 58fc700f3..d70ed6c1c 100644
--- a/crates/completion/src/config.rs
+++ b/crates/completion/src/config.rs
@@ -9,7 +9,7 @@ use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap};
9#[derive(Clone, Debug, PartialEq, Eq)] 9#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct CompletionConfig { 10pub struct CompletionConfig {
11 pub enable_postfix_completions: bool, 11 pub enable_postfix_completions: bool,
12 pub enable_autoimport_completions: bool, 12 pub enable_imports_on_the_fly: bool,
13 pub add_call_parenthesis: bool, 13 pub add_call_parenthesis: bool,
14 pub add_call_argument_snippets: bool, 14 pub add_call_argument_snippets: bool,
15 pub snippet_cap: Option<SnippetCap>, 15 pub snippet_cap: Option<SnippetCap>,
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs
index 0134ff219..d2e6a6aeb 100644
--- a/crates/completion/src/item.rs
+++ b/crates/completion/src/item.rs
@@ -3,11 +3,14 @@
3use std::fmt; 3use std::fmt;
4 4
5use hir::{Documentation, ModPath, Mutability}; 5use hir::{Documentation, ModPath, Mutability};
6use ide_db::helpers::{ 6use ide_db::{
7 insert_use::{self, ImportScope, MergeBehavior}, 7 helpers::{
8 mod_path_to_ast, SnippetCap, 8 insert_use::{self, ImportScope, MergeBehavior},
9 mod_path_to_ast, SnippetCap,
10 },
11 SymbolKind,
9}; 12};
10use stdx::assert_never; 13use stdx::{assert_never, impl_from};
11use syntax::{algo, TextRange}; 14use syntax::{algo, TextRange};
12use text_edit::TextEdit; 15use text_edit::TextEdit;
13 16
@@ -117,49 +120,50 @@ pub enum CompletionScore {
117 120
118#[derive(Debug, Clone, Copy, PartialEq, Eq)] 121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
119pub enum CompletionItemKind { 122pub enum CompletionItemKind {
120 Snippet, 123 SymbolKind(SymbolKind),
121 Keyword, 124 Attribute,
122 Module,
123 Function,
124 BuiltinType,
125 Struct,
126 Enum,
127 EnumVariant,
128 Binding, 125 Binding,
129 Field, 126 BuiltinType,
130 Static, 127 Keyword,
131 Const,
132 Trait,
133 TypeAlias,
134 Method, 128 Method,
135 TypeParam, 129 Snippet,
136 Macro,
137 Attribute,
138 UnresolvedReference, 130 UnresolvedReference,
139} 131}
140 132
133impl_from!(SymbolKind for CompletionItemKind);
134
141impl CompletionItemKind { 135impl CompletionItemKind {
142 #[cfg(test)] 136 #[cfg(test)]
143 pub(crate) fn tag(&self) -> &'static str { 137 pub(crate) fn tag(&self) -> &'static str {
144 match self { 138 match self {
139 CompletionItemKind::SymbolKind(kind) => match kind {
140 SymbolKind::Const => "ct",
141 SymbolKind::ConstParam => "cp",
142 SymbolKind::Enum => "en",
143 SymbolKind::Field => "fd",
144 SymbolKind::Function => "fn",
145 SymbolKind::Impl => "im",
146 SymbolKind::Label => "lb",
147 SymbolKind::LifetimeParam => "lt",
148 SymbolKind::Local => "lc",
149 SymbolKind::Macro => "ma",
150 SymbolKind::Module => "md",
151 SymbolKind::SelfParam => "sp",
152 SymbolKind::Static => "sc",
153 SymbolKind::Struct => "st",
154 SymbolKind::Trait => "tt",
155 SymbolKind::TypeAlias => "ta",
156 SymbolKind::TypeParam => "tp",
157 SymbolKind::Union => "un",
158 SymbolKind::ValueParam => "vp",
159 SymbolKind::Variant => "ev",
160 },
145 CompletionItemKind::Attribute => "at", 161 CompletionItemKind::Attribute => "at",
146 CompletionItemKind::Binding => "bn", 162 CompletionItemKind::Binding => "bn",
147 CompletionItemKind::BuiltinType => "bt", 163 CompletionItemKind::BuiltinType => "bt",
148 CompletionItemKind::Const => "ct",
149 CompletionItemKind::Enum => "en",
150 CompletionItemKind::EnumVariant => "ev",
151 CompletionItemKind::Field => "fd",
152 CompletionItemKind::Function => "fn",
153 CompletionItemKind::Keyword => "kw", 164 CompletionItemKind::Keyword => "kw",
154 CompletionItemKind::Macro => "ma",
155 CompletionItemKind::Method => "me", 165 CompletionItemKind::Method => "me",
156 CompletionItemKind::Module => "md",
157 CompletionItemKind::Snippet => "sn", 166 CompletionItemKind::Snippet => "sn",
158 CompletionItemKind::Static => "sc",
159 CompletionItemKind::Struct => "st",
160 CompletionItemKind::Trait => "tt",
161 CompletionItemKind::TypeAlias => "ta",
162 CompletionItemKind::TypeParam => "tp",
163 CompletionItemKind::UnresolvedReference => "??", 167 CompletionItemKind::UnresolvedReference => "??",
164 } 168 }
165 } 169 }
@@ -270,6 +274,7 @@ impl CompletionItem {
270pub struct ImportEdit { 274pub struct ImportEdit {
271 pub import_path: ModPath, 275 pub import_path: ModPath,
272 pub import_scope: ImportScope, 276 pub import_scope: ImportScope,
277 pub import_for_trait_assoc_item: bool,
273} 278}
274 279
275impl ImportEdit { 280impl ImportEdit {
@@ -321,17 +326,19 @@ impl Builder {
321 let mut insert_text = self.insert_text; 326 let mut insert_text = self.insert_text;
322 327
323 if let Some(import_to_add) = self.import_to_add.as_ref() { 328 if let Some(import_to_add) = self.import_to_add.as_ref() {
324 let mut import_path_without_last_segment = import_to_add.import_path.to_owned(); 329 if import_to_add.import_for_trait_assoc_item {
325 let _ = import_path_without_last_segment.segments.pop(); 330 lookup = lookup.or_else(|| Some(label.clone()));
326 331 insert_text = insert_text.or_else(|| Some(label.clone()));
327 if !import_path_without_last_segment.segments.is_empty() { 332 label = format!("{} ({})", label, import_to_add.import_path);
328 if lookup.is_none() { 333 } else {
329 lookup = Some(label.clone()); 334 let mut import_path_without_last_segment = import_to_add.import_path.to_owned();
330 } 335 let _ = import_path_without_last_segment.segments.pop();
331 if insert_text.is_none() { 336
332 insert_text = Some(label.clone()); 337 if !import_path_without_last_segment.segments.is_empty() {
338 lookup = lookup.or_else(|| Some(label.clone()));
339 insert_text = insert_text.or_else(|| Some(label.clone()));
340 label = format!("{}::{}", import_path_without_last_segment, label);
333 } 341 }
334 label = format!("{}::{}", import_path_without_last_segment, label);
335 } 342 }
336 } 343 }
337 344
@@ -379,8 +386,8 @@ impl Builder {
379 self.insert_text_format = InsertTextFormat::Snippet; 386 self.insert_text_format = InsertTextFormat::Snippet;
380 self.insert_text(snippet) 387 self.insert_text(snippet)
381 } 388 }
382 pub(crate) fn kind(mut self, kind: CompletionItemKind) -> Builder { 389 pub(crate) fn kind(mut self, kind: impl Into<CompletionItemKind>) -> Builder {
383 self.kind = Some(kind); 390 self.kind = Some(kind.into());
384 self 391 self
385 } 392 }
386 pub(crate) fn text_edit(mut self, edit: TextEdit) -> Builder { 393 pub(crate) fn text_edit(mut self, edit: TextEdit) -> Builder {
@@ -398,7 +405,9 @@ impl Builder {
398 pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder { 405 pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder {
399 self.detail = detail.map(Into::into); 406 self.detail = detail.map(Into::into);
400 if let Some(detail) = &self.detail { 407 if let Some(detail) = &self.detail {
401 assert_never!(detail.contains('\n'), "multiline detail: {}", detail); 408 if assert_never!(detail.contains('\n'), "multiline detail: {}", detail) {
409 self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string());
410 }
402 } 411 }
403 self 412 self
404 } 413 }
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs
index ee1b822e7..2c4e54524 100644
--- a/crates/completion/src/lib.rs
+++ b/crates/completion/src/lib.rs
@@ -11,10 +11,10 @@ mod render;
11 11
12mod completions; 12mod completions;
13 13
14use completions::flyimport::position_for_import;
14use ide_db::{ 15use ide_db::{
15 base_db::FilePosition, helpers::insert_use::ImportScope, imports_locator, RootDatabase, 16 base_db::FilePosition, helpers::insert_use::ImportScope, imports_locator, RootDatabase,
16}; 17};
17use syntax::AstNode;
18use text_edit::TextEdit; 18use text_edit::TextEdit;
19 19
20use crate::{completions::Completions, context::CompletionContext, item::CompletionKind}; 20use crate::{completions::Completions, context::CompletionContext, item::CompletionKind};
@@ -139,12 +139,13 @@ pub fn resolve_completion_edits(
139 position: FilePosition, 139 position: FilePosition,
140 full_import_path: &str, 140 full_import_path: &str,
141 imported_name: String, 141 imported_name: String,
142 import_for_trait_assoc_item: bool,
142) -> Option<Vec<TextEdit>> { 143) -> Option<Vec<TextEdit>> {
143 let ctx = CompletionContext::new(db, position, config)?; 144 let ctx = CompletionContext::new(db, position, config)?;
144 let anchor = ctx.name_ref_syntax.as_ref()?; 145 let position_for_import = position_for_import(&ctx, None)?;
145 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; 146 let import_scope = ImportScope::find_insert_use_container(position_for_import, &ctx.sema)?;
146 147
147 let current_module = ctx.sema.scope(anchor.syntax()).module()?; 148 let current_module = ctx.sema.scope(position_for_import).module()?;
148 let current_crate = current_module.krate(); 149 let current_crate = current_module.krate();
149 150
150 let import_path = imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name) 151 let import_path = imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name)
@@ -154,7 +155,7 @@ pub fn resolve_completion_edits(
154 }) 155 })
155 .find(|mod_path| mod_path.to_string() == full_import_path)?; 156 .find(|mod_path| mod_path.to_string() == full_import_path)?;
156 157
157 ImportEdit { import_path, import_scope } 158 ImportEdit { import_path, import_scope, import_for_trait_assoc_item }
158 .to_text_edit(config.insert_use.merge) 159 .to_text_edit(config.insert_use.merge)
159 .map(|edit| vec![edit]) 160 .map(|edit| vec![edit])
160} 161}
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs
index 820dd01d1..fa594b5e5 100644
--- a/crates/completion/src/render.rs
+++ b/crates/completion/src/render.rs
@@ -10,8 +10,10 @@ pub(crate) mod type_alias;
10 10
11mod builder_ext; 11mod builder_ext;
12 12
13use hir::{Documentation, HasAttrs, HirDisplay, Mutability, ScopeDef, Type}; 13use hir::{
14use ide_db::{helpers::SnippetCap, RootDatabase}; 14 AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type,
15};
16use ide_db::{helpers::SnippetCap, RootDatabase, SymbolKind};
15use syntax::TextRange; 17use syntax::TextRange;
16use test_utils::mark; 18use test_utils::mark;
17 19
@@ -51,16 +53,16 @@ pub(crate) fn render_resolution_with_import<'a>(
51 import_edit: ImportEdit, 53 import_edit: ImportEdit,
52 resolution: &ScopeDef, 54 resolution: &ScopeDef,
53) -> Option<CompletionItem> { 55) -> Option<CompletionItem> {
54 Render::new(ctx) 56 let local_name = match resolution {
55 .render_resolution( 57 ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(),
56 import_edit.import_path.segments.last()?.to_string(), 58 ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(),
57 Some(import_edit), 59 ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(),
58 resolution, 60 _ => import_edit.import_path.segments.last()?.to_string(),
59 ) 61 };
60 .map(|mut item| { 62 Render::new(ctx).render_resolution(local_name, Some(import_edit), resolution).map(|mut item| {
61 item.completion_kind = CompletionKind::Magic; 63 item.completion_kind = CompletionKind::Magic;
62 item 64 item
63 }) 65 })
64} 66}
65 67
66/// Interface for data and methods required for items rendering. 68/// Interface for data and methods required for items rendering.
@@ -87,7 +89,24 @@ impl<'a> RenderContext<'a> {
87 } 89 }
88 90
89 fn is_deprecated(&self, node: impl HasAttrs) -> bool { 91 fn is_deprecated(&self, node: impl HasAttrs) -> bool {
90 node.attrs(self.db()).by_key("deprecated").exists() 92 let attrs = node.attrs(self.db());
93 attrs.by_key("deprecated").exists() || attrs.by_key("rustc_deprecated").exists()
94 }
95
96 fn is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool {
97 let db = self.db();
98 let assoc = match as_assoc_item.as_assoc_item(db) {
99 Some(assoc) => assoc,
100 None => return false,
101 };
102
103 let is_assoc_deprecated = match assoc {
104 hir::AssocItem::Function(it) => self.is_deprecated(it),
105 hir::AssocItem::Const(it) => self.is_deprecated(it),
106 hir::AssocItem::TypeAlias(it) => self.is_deprecated(it),
107 };
108 is_assoc_deprecated
109 || assoc.containing_trait(db).map(|trait_| self.is_deprecated(trait_)).unwrap_or(false)
91 } 110 }
92 111
93 fn docs(&self, node: impl HasAttrs) -> Option<Documentation> { 112 fn docs(&self, node: impl HasAttrs) -> Option<Documentation> {
@@ -127,7 +146,7 @@ impl<'a> Render<'a> {
127 self.ctx.source_range(), 146 self.ctx.source_range(),
128 name.to_string(), 147 name.to_string(),
129 ) 148 )
130 .kind(CompletionItemKind::Field) 149 .kind(SymbolKind::Field)
131 .detail(ty.display(self.ctx.db()).to_string()) 150 .detail(ty.display(self.ctx.db()).to_string())
132 .set_documentation(field.docs(self.ctx.db())) 151 .set_documentation(field.docs(self.ctx.db()))
133 .set_deprecated(is_deprecated); 152 .set_deprecated(is_deprecated);
@@ -141,7 +160,7 @@ impl<'a> Render<'a> {
141 160
142 fn add_tuple_field(&mut self, field: usize, ty: &Type) -> CompletionItem { 161 fn add_tuple_field(&mut self, field: usize, ty: &Type) -> CompletionItem {
143 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), field.to_string()) 162 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), field.to_string())
144 .kind(CompletionItemKind::Field) 163 .kind(SymbolKind::Field)
145 .detail(ty.display(self.ctx.db()).to_string()) 164 .detail(ty.display(self.ctx.db()).to_string())
146 .build() 165 .build()
147 } 166 }
@@ -168,7 +187,7 @@ impl<'a> Render<'a> {
168 if self.ctx.completion.is_pat_binding_or_const 187 if self.ctx.completion.is_pat_binding_or_const
169 | self.ctx.completion.is_irrefutable_pat_binding => 188 | self.ctx.completion.is_irrefutable_pat_binding =>
170 { 189 {
171 CompletionItemKind::EnumVariant 190 CompletionItemKind::SymbolKind(SymbolKind::Variant)
172 } 191 }
173 ScopeDef::ModuleDef(Variant(var)) => { 192 ScopeDef::ModuleDef(Variant(var)) => {
174 let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); 193 let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None);
@@ -179,20 +198,29 @@ impl<'a> Render<'a> {
179 return item; 198 return item;
180 } 199 }
181 200
182 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module, 201 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
183 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct, 202 ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
184 // FIXME: add CompletionItemKind::Union 203 hir::Adt::Struct(_) => SymbolKind::Struct,
185 ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct, 204 // FIXME: add CompletionItemKind::Union
186 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum, 205 hir::Adt::Union(_) => SymbolKind::Struct,
187 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const, 206 hir::Adt::Enum(_) => SymbolKind::Enum,
188 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static, 207 }),
189 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait, 208 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
190 ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias, 209 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
210 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
211 ScopeDef::ModuleDef(TypeAlias(..)) => {
212 CompletionItemKind::SymbolKind(SymbolKind::TypeAlias)
213 }
191 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, 214 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
192 ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam, 215 ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
193 ScopeDef::Local(..) => CompletionItemKind::Binding, 216 hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
194 // (does this need its own kind?) 217 hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
195 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam, 218 hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
219 }),
220 ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
221 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => {
222 CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
223 }
196 ScopeDef::Unknown => { 224 ScopeDef::Unknown => {
197 let item = CompletionItem::new( 225 let item = CompletionItem::new(
198 CompletionKind::Reference, 226 CompletionKind::Reference,
@@ -206,8 +234,6 @@ impl<'a> Render<'a> {
206 } 234 }
207 }; 235 };
208 236
209 let docs = self.docs(resolution);
210
211 let mut item = 237 let mut item =
212 CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone()); 238 CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone());
213 if let ScopeDef::Local(local) = resolution { 239 if let ScopeDef::Local(local) = resolution {
@@ -253,13 +279,14 @@ impl<'a> Render<'a> {
253 } 279 }
254 } 280 }
255 281
256 let item = item 282 Some(
257 .kind(kind) 283 item.kind(kind)
258 .add_import(import_to_add) 284 .add_import(import_to_add)
259 .set_documentation(docs) 285 .set_ref_match(ref_match)
260 .set_ref_match(ref_match) 286 .set_documentation(self.docs(resolution))
261 .build(); 287 .set_deprecated(self.is_deprecated(resolution))
262 Some(item) 288 .build(),
289 )
263 } 290 }
264 291
265 fn docs(&self, resolution: &ScopeDef) -> Option<Documentation> { 292 fn docs(&self, resolution: &ScopeDef) -> Option<Documentation> {
@@ -275,6 +302,16 @@ impl<'a> Render<'a> {
275 _ => None, 302 _ => None,
276 } 303 }
277 } 304 }
305
306 fn is_deprecated(&self, resolution: &ScopeDef) -> bool {
307 match resolution {
308 ScopeDef::ModuleDef(it) => self.ctx.is_deprecated_assoc_item(*it),
309 ScopeDef::MacroDef(it) => self.ctx.is_deprecated(*it),
310 ScopeDef::GenericParam(it) => self.ctx.is_deprecated(*it),
311 ScopeDef::AdtSelfType(it) => self.ctx.is_deprecated(*it),
312 _ => false,
313 }
314 }
278} 315}
279 316
280fn compute_score_from_active( 317fn compute_score_from_active(
@@ -372,7 +409,9 @@ fn main() { Foo::Fo$0 }
372 source_range: 54..56, 409 source_range: 54..56,
373 delete: 54..56, 410 delete: 54..56,
374 insert: "Foo", 411 insert: "Foo",
375 kind: EnumVariant, 412 kind: SymbolKind(
413 Variant,
414 ),
376 detail: "{ x: i32, y: i32 }", 415 detail: "{ x: i32, y: i32 }",
377 }, 416 },
378 ] 417 ]
@@ -395,7 +434,9 @@ fn main() { Foo::Fo$0 }
395 source_range: 46..48, 434 source_range: 46..48,
396 delete: 46..48, 435 delete: 46..48,
397 insert: "Foo($0)", 436 insert: "Foo($0)",
398 kind: EnumVariant, 437 kind: SymbolKind(
438 Variant,
439 ),
399 lookup: "Foo", 440 lookup: "Foo",
400 detail: "(i32, i32)", 441 detail: "(i32, i32)",
401 trigger_call_info: true, 442 trigger_call_info: true,
@@ -420,7 +461,9 @@ fn main() { Foo::Fo$0 }
420 source_range: 35..37, 461 source_range: 35..37,
421 delete: 35..37, 462 delete: 35..37,
422 insert: "Foo", 463 insert: "Foo",
423 kind: EnumVariant, 464 kind: SymbolKind(
465 Variant,
466 ),
424 detail: "()", 467 detail: "()",
425 }, 468 },
426 ] 469 ]
@@ -444,7 +487,9 @@ fn main() { let _: m::Spam = S$0 }
444 source_range: 75..76, 487 source_range: 75..76,
445 delete: 75..76, 488 delete: 75..76,
446 insert: "Spam::Bar($0)", 489 insert: "Spam::Bar($0)",
447 kind: EnumVariant, 490 kind: SymbolKind(
491 Variant,
492 ),
448 lookup: "Spam::Bar", 493 lookup: "Spam::Bar",
449 detail: "(i32)", 494 detail: "(i32)",
450 trigger_call_info: true, 495 trigger_call_info: true,
@@ -454,14 +499,18 @@ fn main() { let _: m::Spam = S$0 }
454 source_range: 75..76, 499 source_range: 75..76,
455 delete: 75..76, 500 delete: 75..76,
456 insert: "m", 501 insert: "m",
457 kind: Module, 502 kind: SymbolKind(
503 Module,
504 ),
458 }, 505 },
459 CompletionItem { 506 CompletionItem {
460 label: "m::Spam::Foo", 507 label: "m::Spam::Foo",
461 source_range: 75..76, 508 source_range: 75..76,
462 delete: 75..76, 509 delete: 75..76,
463 insert: "m::Spam::Foo", 510 insert: "m::Spam::Foo",
464 kind: EnumVariant, 511 kind: SymbolKind(
512 Variant,
513 ),
465 lookup: "Spam::Foo", 514 lookup: "Spam::Foo",
466 detail: "()", 515 detail: "()",
467 }, 516 },
@@ -470,7 +519,9 @@ fn main() { let _: m::Spam = S$0 }
470 source_range: 75..76, 519 source_range: 75..76,
471 delete: 75..76, 520 delete: 75..76,
472 insert: "main()$0", 521 insert: "main()$0",
473 kind: Function, 522 kind: SymbolKind(
523 Function,
524 ),
474 lookup: "main", 525 lookup: "main",
475 detail: "fn main()", 526 detail: "fn main()",
476 }, 527 },
@@ -485,7 +536,7 @@ fn main() { let _: m::Spam = S$0 }
485 r#" 536 r#"
486#[deprecated] 537#[deprecated]
487fn something_deprecated() {} 538fn something_deprecated() {}
488#[deprecated(since = "1.0.0")] 539#[rustc_deprecated(since = "1.0.0")]
489fn something_else_deprecated() {} 540fn something_else_deprecated() {}
490 541
491fn main() { som$0 } 542fn main() { som$0 }
@@ -494,29 +545,35 @@ fn main() { som$0 }
494 [ 545 [
495 CompletionItem { 546 CompletionItem {
496 label: "main()", 547 label: "main()",
497 source_range: 121..124, 548 source_range: 127..130,
498 delete: 121..124, 549 delete: 127..130,
499 insert: "main()$0", 550 insert: "main()$0",
500 kind: Function, 551 kind: SymbolKind(
552 Function,
553 ),
501 lookup: "main", 554 lookup: "main",
502 detail: "fn main()", 555 detail: "fn main()",
503 }, 556 },
504 CompletionItem { 557 CompletionItem {
505 label: "something_deprecated()", 558 label: "something_deprecated()",
506 source_range: 121..124, 559 source_range: 127..130,
507 delete: 121..124, 560 delete: 127..130,
508 insert: "something_deprecated()$0", 561 insert: "something_deprecated()$0",
509 kind: Function, 562 kind: SymbolKind(
563 Function,
564 ),
510 lookup: "something_deprecated", 565 lookup: "something_deprecated",
511 detail: "fn something_deprecated()", 566 detail: "fn something_deprecated()",
512 deprecated: true, 567 deprecated: true,
513 }, 568 },
514 CompletionItem { 569 CompletionItem {
515 label: "something_else_deprecated()", 570 label: "something_else_deprecated()",
516 source_range: 121..124, 571 source_range: 127..130,
517 delete: 121..124, 572 delete: 127..130,
518 insert: "something_else_deprecated()$0", 573 insert: "something_else_deprecated()$0",
519 kind: Function, 574 kind: SymbolKind(
575 Function,
576 ),
520 lookup: "something_else_deprecated", 577 lookup: "something_else_deprecated",
521 detail: "fn something_else_deprecated()", 578 detail: "fn something_else_deprecated()",
522 deprecated: true, 579 deprecated: true,
@@ -537,7 +594,9 @@ fn foo() { A { the$0 } }
537 source_range: 57..60, 594 source_range: 57..60,
538 delete: 57..60, 595 delete: 57..60,
539 insert: "the_field", 596 insert: "the_field",
540 kind: Field, 597 kind: SymbolKind(
598 Field,
599 ),
541 detail: "u32", 600 detail: "u32",
542 deprecated: true, 601 deprecated: true,
543 }, 602 },
@@ -577,7 +636,9 @@ impl S {
577 source_range: 94..94, 636 source_range: 94..94,
578 delete: 94..94, 637 delete: 94..94,
579 insert: "foo", 638 insert: "foo",
580 kind: Field, 639 kind: SymbolKind(
640 Field,
641 ),
581 detail: "{unknown}", 642 detail: "{unknown}",
582 documentation: Documentation( 643 documentation: Documentation(
583 "Field docs", 644 "Field docs",
@@ -608,7 +669,9 @@ use self::E::*;
608 source_range: 10..12, 669 source_range: 10..12,
609 delete: 10..12, 670 delete: 10..12,
610 insert: "E", 671 insert: "E",
611 kind: Enum, 672 kind: SymbolKind(
673 Enum,
674 ),
612 documentation: Documentation( 675 documentation: Documentation(
613 "enum docs", 676 "enum docs",
614 ), 677 ),
@@ -618,7 +681,9 @@ use self::E::*;
618 source_range: 10..12, 681 source_range: 10..12,
619 delete: 10..12, 682 delete: 10..12,
620 insert: "V", 683 insert: "V",
621 kind: EnumVariant, 684 kind: SymbolKind(
685 Variant,
686 ),
622 detail: "()", 687 detail: "()",
623 documentation: Documentation( 688 documentation: Documentation(
624 "variant docs", 689 "variant docs",
@@ -629,7 +694,9 @@ use self::E::*;
629 source_range: 10..12, 694 source_range: 10..12,
630 delete: 10..12, 695 delete: 10..12,
631 insert: "my", 696 insert: "my",
632 kind: Module, 697 kind: SymbolKind(
698 Module,
699 ),
633 documentation: Documentation( 700 documentation: Documentation(
634 "mod docs", 701 "mod docs",
635 ), 702 ),
@@ -855,7 +922,7 @@ struct WorldSnapshot { _f: () };
855fn go(world: &WorldSnapshot) { go(w$0) } 922fn go(world: &WorldSnapshot) { go(w$0) }
856"#, 923"#,
857 expect![[r#" 924 expect![[r#"
858 bn world [type+name] 925 lc world [type+name]
859 st WorldSnapshot [] 926 st WorldSnapshot []
860 fn go(…) [] 927 fn go(…) []
861 "#]], 928 "#]],
@@ -872,7 +939,7 @@ fn f(foo: &Foo) { f(foo, w$0) }
872 expect![[r#" 939 expect![[r#"
873 st Foo [] 940 st Foo []
874 fn f(…) [] 941 fn f(…) []
875 bn foo [] 942 lc foo []
876 "#]], 943 "#]],
877 ); 944 );
878 } 945 }
diff --git a/crates/completion/src/render/const_.rs b/crates/completion/src/render/const_.rs
index ce924f309..5010b642a 100644
--- a/crates/completion/src/render/const_.rs
+++ b/crates/completion/src/render/const_.rs
@@ -1,13 +1,14 @@
1//! Renderer for `const` fields. 1//! Renderer for `const` fields.
2 2
3use hir::HasSource; 3use hir::HasSource;
4use ide_db::SymbolKind;
4use syntax::{ 5use syntax::{
5 ast::{Const, NameOwner}, 6 ast::{Const, NameOwner},
6 display::const_label, 7 display::const_label,
7}; 8};
8 9
9use crate::{ 10use crate::{
10 item::{CompletionItem, CompletionItemKind, CompletionKind}, 11 item::{CompletionItem, CompletionKind},
11 render::RenderContext, 12 render::RenderContext,
12}; 13};
13 14
@@ -36,9 +37,12 @@ impl<'a> ConstRender<'a> {
36 let detail = self.detail(); 37 let detail = self.detail();
37 38
38 let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) 39 let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name)
39 .kind(CompletionItemKind::Const) 40 .kind(SymbolKind::Const)
40 .set_documentation(self.ctx.docs(self.const_)) 41 .set_documentation(self.ctx.docs(self.const_))
41 .set_deprecated(self.ctx.is_deprecated(self.const_)) 42 .set_deprecated(
43 self.ctx.is_deprecated(self.const_)
44 || self.ctx.is_deprecated_assoc_item(self.const_),
45 )
42 .detail(detail) 46 .detail(detail)
43 .build(); 47 .build();
44 48
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs
index 89fb49773..adcddebd1 100644
--- a/crates/completion/src/render/enum_variant.rs
+++ b/crates/completion/src/render/enum_variant.rs
@@ -1,11 +1,12 @@
1//! Renderer for `enum` variants. 1//! Renderer for `enum` variants.
2 2
3use hir::{HasAttrs, HirDisplay, ModPath, StructKind}; 3use hir::{HasAttrs, HirDisplay, ModPath, StructKind};
4use ide_db::SymbolKind;
4use itertools::Itertools; 5use itertools::Itertools;
5use test_utils::mark; 6use test_utils::mark;
6 7
7use crate::{ 8use crate::{
8 item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit}, 9 item::{CompletionItem, CompletionKind, ImportEdit},
9 render::{builder_ext::Params, RenderContext}, 10 render::{builder_ext::Params, RenderContext},
10}; 11};
11 12
@@ -60,7 +61,7 @@ impl<'a> EnumRender<'a> {
60 self.ctx.source_range(), 61 self.ctx.source_range(),
61 self.qualified_name.clone(), 62 self.qualified_name.clone(),
62 ) 63 )
63 .kind(CompletionItemKind::EnumVariant) 64 .kind(SymbolKind::Variant)
64 .set_documentation(self.variant.docs(self.ctx.db())) 65 .set_documentation(self.variant.docs(self.ctx.db()))
65 .set_deprecated(self.ctx.is_deprecated(self.variant)) 66 .set_deprecated(self.ctx.is_deprecated(self.variant))
66 .add_import(import_to_add) 67 .add_import(import_to_add)
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs
index f5b0ce3e3..2d616b1fb 100644
--- a/crates/completion/src/render/function.rs
+++ b/crates/completion/src/render/function.rs
@@ -1,6 +1,7 @@
1//! Renderer for function calls. 1//! Renderer for function calls.
2 2
3use hir::{HasSource, Type}; 3use hir::{HasSource, Type};
4use ide_db::SymbolKind;
4use syntax::{ast::Fn, display::function_declaration}; 5use syntax::{ast::Fn, display::function_declaration};
5use test_utils::mark; 6use test_utils::mark;
6 7
@@ -44,7 +45,9 @@ impl<'a> FunctionRender<'a> {
44 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) 45 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone())
45 .kind(self.kind()) 46 .kind(self.kind())
46 .set_documentation(self.ctx.docs(self.func)) 47 .set_documentation(self.ctx.docs(self.func))
47 .set_deprecated(self.ctx.is_deprecated(self.func)) 48 .set_deprecated(
49 self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func),
50 )
48 .detail(self.detail()) 51 .detail(self.detail())
49 .add_call_parens(self.ctx.completion, self.name, params) 52 .add_call_parens(self.ctx.completion, self.name, params)
50 .add_import(import_to_add) 53 .add_import(import_to_add)
@@ -103,7 +106,7 @@ impl<'a> FunctionRender<'a> {
103 if self.func.self_param(self.ctx.db()).is_some() { 106 if self.func.self_param(self.ctx.db()).is_some() {
104 CompletionItemKind::Method 107 CompletionItemKind::Method
105 } else { 108 } else {
106 CompletionItemKind::Function 109 SymbolKind::Function.into()
107 } 110 }
108 } 111 }
109} 112}
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs
index f893e420a..a4535786f 100644
--- a/crates/completion/src/render/macro_.rs
+++ b/crates/completion/src/render/macro_.rs
@@ -1,11 +1,12 @@
1//! Renderer for macro invocations. 1//! Renderer for macro invocations.
2 2
3use hir::{Documentation, HasSource}; 3use hir::{Documentation, HasSource};
4use ide_db::SymbolKind;
4use syntax::display::macro_label; 5use syntax::display::macro_label;
5use test_utils::mark; 6use test_utils::mark;
6 7
7use crate::{ 8use crate::{
8 item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit}, 9 item::{CompletionItem, CompletionKind, ImportEdit},
9 render::RenderContext, 10 render::RenderContext,
10}; 11};
11 12
@@ -41,7 +42,7 @@ impl<'a> MacroRender<'a> {
41 fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> { 42 fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
42 let mut builder = 43 let mut builder =
43 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label()) 44 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label())
44 .kind(CompletionItemKind::Macro) 45 .kind(SymbolKind::Macro)
45 .set_documentation(self.docs.clone()) 46 .set_documentation(self.docs.clone())
46 .set_deprecated(self.ctx.is_deprecated(self.macro_)) 47 .set_deprecated(self.ctx.is_deprecated(self.macro_))
47 .add_import(import_to_add) 48 .add_import(import_to_add)
diff --git a/crates/completion/src/render/type_alias.rs b/crates/completion/src/render/type_alias.rs
index 69b445b9c..bd97c3692 100644
--- a/crates/completion/src/render/type_alias.rs
+++ b/crates/completion/src/render/type_alias.rs
@@ -1,13 +1,14 @@
1//! Renderer for type aliases. 1//! Renderer for type aliases.
2 2
3use hir::HasSource; 3use hir::HasSource;
4use ide_db::SymbolKind;
4use syntax::{ 5use syntax::{
5 ast::{NameOwner, TypeAlias}, 6 ast::{NameOwner, TypeAlias},
6 display::type_label, 7 display::type_label,
7}; 8};
8 9
9use crate::{ 10use crate::{
10 item::{CompletionItem, CompletionItemKind, CompletionKind}, 11 item::{CompletionItem, CompletionKind},
11 render::RenderContext, 12 render::RenderContext,
12}; 13};
13 14
@@ -36,9 +37,12 @@ impl<'a> TypeAliasRender<'a> {
36 let detail = self.detail(); 37 let detail = self.detail();
37 38
38 let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) 39 let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name)
39 .kind(CompletionItemKind::TypeAlias) 40 .kind(SymbolKind::TypeAlias)
40 .set_documentation(self.ctx.docs(self.type_alias)) 41 .set_documentation(self.ctx.docs(self.type_alias))
41 .set_deprecated(self.ctx.is_deprecated(self.type_alias)) 42 .set_deprecated(
43 self.ctx.is_deprecated(self.type_alias)
44 || self.ctx.is_deprecated_assoc_item(self.type_alias),
45 )
42 .detail(detail) 46 .detail(detail)
43 .build(); 47 .build();
44 48
diff --git a/crates/completion/src/test_utils.rs b/crates/completion/src/test_utils.rs
index 6ea6da989..baff83305 100644
--- a/crates/completion/src/test_utils.rs
+++ b/crates/completion/src/test_utils.rs
@@ -18,7 +18,7 @@ use crate::{item::CompletionKind, CompletionConfig, CompletionItem};
18 18
19pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { 19pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
20 enable_postfix_completions: true, 20 enable_postfix_completions: true,
21 enable_autoimport_completions: true, 21 enable_imports_on_the_fly: true,
22 add_call_parenthesis: true, 22 add_call_parenthesis: true,
23 add_call_argument_snippets: true, 23 add_call_argument_snippets: true,
24 snippet_cap: SnippetCap::new(true), 24 snippet_cap: SnippetCap::new(true),
@@ -83,6 +83,9 @@ pub(crate) fn completion_list_with_config(
83 let width = label_width.saturating_sub(monospace_width(it.label())); 83 let width = label_width.saturating_sub(monospace_width(it.label()));
84 format_to!(buf, "{:width$} {}", "", detail, width = width); 84 format_to!(buf, "{:width$} {}", "", detail, width = width);
85 } 85 }
86 if it.deprecated() {
87 format_to!(buf, " DEPRECATED");
88 }
86 format_to!(buf, "\n"); 89 format_to!(buf, "\n");
87 buf 90 buf
88 }) 91 })
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 99fb65bac..9e6a3e155 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -2,6 +2,7 @@
2use hir_def::{ 2use hir_def::{
3 attr::{Attrs, Documentation}, 3 attr::{Attrs, Documentation},
4 path::ModPath, 4 path::ModPath,
5 per_ns::PerNs,
5 resolver::HasResolver, 6 resolver::HasResolver,
6 AttrDefId, GenericParamId, ModuleDefId, 7 AttrDefId, GenericParamId, ModuleDefId,
7}; 8};
@@ -112,6 +113,11 @@ fn resolve_doc_path(
112 let path = ast::Path::parse(link).ok()?; 113 let path = ast::Path::parse(link).ok()?;
113 let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap(); 114 let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap();
114 let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); 115 let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath);
116 if resolved == PerNs::none() {
117 if let Some(trait_id) = resolver.resolve_module_path_in_trait_items(db.upcast(), &modpath) {
118 return Some(ModuleDefId::TraitId(trait_id));
119 };
120 }
115 let def = match ns { 121 let def = match ns {
116 Some(Namespace::Types) => resolved.take_types()?, 122 Some(Namespace::Types) => resolved.take_types()?,
117 Some(Namespace::Values) => resolved.take_values()?, 123 Some(Namespace::Values) => resolved.take_values()?,
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index 6cbf5cecf..c34a99d90 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -90,7 +90,7 @@ impl Crate {
90 } 90 }
91 91
92 pub fn root_module(self, db: &dyn HirDatabase) -> Module { 92 pub fn root_module(self, db: &dyn HirDatabase) -> Module {
93 let module_id = db.crate_def_map(self.id).root; 93 let module_id = db.crate_def_map(self.id).root();
94 Module::new(self, module_id) 94 Module::new(self, module_id)
95 } 95 }
96 96
@@ -281,7 +281,7 @@ impl Module {
281 281
282 /// Name of this module. 282 /// Name of this module.
283 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { 283 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
284 let def_map = db.crate_def_map(self.id.krate); 284 let def_map = self.id.def_map(db.upcast());
285 let parent = def_map[self.id.local_id].parent?; 285 let parent = def_map[self.id.local_id].parent?;
286 def_map[parent].children.iter().find_map(|(name, module_id)| { 286 def_map[parent].children.iter().find_map(|(name, module_id)| {
287 if *module_id == self.id.local_id { 287 if *module_id == self.id.local_id {
@@ -302,12 +302,12 @@ impl Module {
302 /// in the module tree of any target in `Cargo.toml`. 302 /// in the module tree of any target in `Cargo.toml`.
303 pub fn crate_root(self, db: &dyn HirDatabase) -> Module { 303 pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
304 let def_map = db.crate_def_map(self.id.krate); 304 let def_map = db.crate_def_map(self.id.krate);
305 self.with_module_id(def_map.root) 305 self.with_module_id(def_map.root())
306 } 306 }
307 307
308 /// Iterates over all child modules. 308 /// Iterates over all child modules.
309 pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> { 309 pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> {
310 let def_map = db.crate_def_map(self.id.krate); 310 let def_map = self.id.def_map(db.upcast());
311 let children = def_map[self.id.local_id] 311 let children = def_map[self.id.local_id]
312 .children 312 .children
313 .iter() 313 .iter()
@@ -318,7 +318,7 @@ impl Module {
318 318
319 /// Finds a parent module. 319 /// Finds a parent module.
320 pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> { 320 pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> {
321 let def_map = db.crate_def_map(self.id.krate); 321 let def_map = self.id.def_map(db.upcast());
322 let parent_id = def_map[self.id.local_id].parent?; 322 let parent_id = def_map[self.id.local_id].parent?;
323 Some(self.with_module_id(parent_id)) 323 Some(self.with_module_id(parent_id))
324 } 324 }
@@ -339,7 +339,7 @@ impl Module {
339 db: &dyn HirDatabase, 339 db: &dyn HirDatabase,
340 visible_from: Option<Module>, 340 visible_from: Option<Module>,
341 ) -> Vec<(Name, ScopeDef)> { 341 ) -> Vec<(Name, ScopeDef)> {
342 db.crate_def_map(self.id.krate)[self.id.local_id] 342 self.id.def_map(db.upcast())[self.id.local_id]
343 .scope 343 .scope
344 .entries() 344 .entries()
345 .filter_map(|(name, def)| { 345 .filter_map(|(name, def)| {
@@ -362,14 +362,14 @@ impl Module {
362 } 362 }
363 363
364 pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> { 364 pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> {
365 db.crate_def_map(self.id.krate)[self.id.local_id].scope.visibility_of(def.clone().into()) 365 self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into())
366 } 366 }
367 367
368 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 368 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
369 let _p = profile::span("Module::diagnostics").detail(|| { 369 let _p = profile::span("Module::diagnostics").detail(|| {
370 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) 370 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
371 }); 371 });
372 let crate_def_map = db.crate_def_map(self.id.krate); 372 let crate_def_map = self.id.def_map(db.upcast());
373 crate_def_map.add_diagnostics(db.upcast(), self.id.local_id, sink); 373 crate_def_map.add_diagnostics(db.upcast(), self.id.local_id, sink);
374 for decl in self.declarations(db) { 374 for decl in self.declarations(db) {
375 match decl { 375 match decl {
@@ -396,12 +396,12 @@ impl Module {
396 } 396 }
397 397
398 pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> { 398 pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> {
399 let def_map = db.crate_def_map(self.id.krate); 399 let def_map = self.id.def_map(db.upcast());
400 def_map[self.id.local_id].scope.declarations().map(ModuleDef::from).collect() 400 def_map[self.id.local_id].scope.declarations().map(ModuleDef::from).collect()
401 } 401 }
402 402
403 pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> { 403 pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> {
404 let def_map = db.crate_def_map(self.id.krate); 404 let def_map = self.id.def_map(db.upcast());
405 def_map[self.id.local_id].scope.impls().map(Impl::from).collect() 405 def_map[self.id.local_id].scope.impls().map(Impl::from).collect()
406 } 406 }
407 407
@@ -1000,7 +1000,7 @@ impl MacroDef {
1000 /// early, in `hir_expand`, where modules simply do not exist yet. 1000 /// early, in `hir_expand`, where modules simply do not exist yet.
1001 pub fn module(self, db: &dyn HirDatabase) -> Option<Module> { 1001 pub fn module(self, db: &dyn HirDatabase) -> Option<Module> {
1002 let krate = self.id.krate; 1002 let krate = self.id.krate;
1003 let module_id = db.crate_def_map(krate).root; 1003 let module_id = db.crate_def_map(krate).root();
1004 Some(Module::new(Crate { id: krate }, module_id)) 1004 Some(Module::new(Crate { id: krate }, module_id))
1005 } 1005 }
1006 1006
@@ -1051,6 +1051,16 @@ impl AsAssocItem for TypeAlias {
1051 as_assoc_item(db, AssocItem::TypeAlias, self.id) 1051 as_assoc_item(db, AssocItem::TypeAlias, self.id)
1052 } 1052 }
1053} 1053}
1054impl AsAssocItem for ModuleDef {
1055 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
1056 match self {
1057 ModuleDef::Function(it) => it.as_assoc_item(db),
1058 ModuleDef::Const(it) => it.as_assoc_item(db),
1059 ModuleDef::TypeAlias(it) => it.as_assoc_item(db),
1060 _ => None,
1061 }
1062 }
1063}
1054fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem> 1064fn as_assoc_item<ID, DEF, CTOR, AST>(db: &dyn HirDatabase, ctor: CTOR, id: ID) -> Option<AssocItem>
1055where 1065where
1056 ID: Lookup<Data = AssocItemLoc<AST>>, 1066 ID: Lookup<Data = AssocItemLoc<AST>>,
@@ -1091,6 +1101,13 @@ impl AssocItem {
1091 AssocContainerId::ContainerId(_) => panic!("invalid AssocItem"), 1101 AssocContainerId::ContainerId(_) => panic!("invalid AssocItem"),
1092 } 1102 }
1093 } 1103 }
1104
1105 pub fn containing_trait(self, db: &dyn HirDatabase) -> Option<Trait> {
1106 match self.container(db) {
1107 AssocItemContainer::Trait(t) => Some(t),
1108 _ => None,
1109 }
1110 }
1094} 1111}
1095 1112
1096impl HasVisibility for AssocItem { 1113impl HasVisibility for AssocItem {
@@ -2029,7 +2046,7 @@ impl Callable {
2029pub enum ScopeDef { 2046pub enum ScopeDef {
2030 ModuleDef(ModuleDef), 2047 ModuleDef(ModuleDef),
2031 MacroDef(MacroDef), 2048 MacroDef(MacroDef),
2032 GenericParam(TypeParam), 2049 GenericParam(GenericParam),
2033 ImplSelfType(Impl), 2050 ImplSelfType(Impl),
2034 AdtSelfType(Adt), 2051 AdtSelfType(Adt),
2035 Local(Local), 2052 Local(Local),
diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs
index d5d4cf5b6..d444f4bbb 100644
--- a/crates/hir/src/db.rs
+++ b/crates/hir/src/db.rs
@@ -1,13 +1,13 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3pub use hir_def::db::{ 3pub use hir_def::db::{
4 AttrsQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQueryQuery, 4 AttrsQuery, BlockDefMapQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery,
5 CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, EnumDataQuery, ExprScopesQuery, 5 CrateDefMapQueryQuery, CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, EnumDataQuery,
6 FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery, InternConstQuery, 6 ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery,
7 InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, InternImplQuery, 7 InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery,
8 InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, InternUnionQuery, 8 InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery,
9 ItemTreeQuery, LangItemQuery, StaticDataQuery, StructDataQuery, TraitDataQuery, 9 InternUnionQuery, ItemTreeQuery, LangItemQuery, StaticDataQuery, StructDataQuery,
10 TypeAliasDataQuery, UnionDataQuery, 10 TraitDataQuery, TypeAliasDataQuery, UnionDataQuery,
11}; 11};
12pub use hir_expand::db::{ 12pub use hir_expand::db::{
13 AstDatabase, AstDatabaseStorage, AstIdMapQuery, HygieneFrameQuery, InternEagerExpansionQuery, 13 AstDatabase, AstDatabaseStorage, AstIdMapQuery, HygieneFrameQuery, InternEagerExpansionQuery,
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 7c57d8378..262002671 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -24,12 +24,12 @@ pub trait HasSource {
24impl Module { 24impl Module {
25 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. 25 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
26 pub fn definition_source(self, db: &dyn HirDatabase) -> InFile<ModuleSource> { 26 pub fn definition_source(self, db: &dyn HirDatabase) -> InFile<ModuleSource> {
27 let def_map = db.crate_def_map(self.id.krate); 27 let def_map = self.id.def_map(db.upcast());
28 def_map[self.id.local_id].definition_source(db.upcast()) 28 def_map[self.id.local_id].definition_source(db.upcast())
29 } 29 }
30 30
31 pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool { 31 pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool {
32 let def_map = db.crate_def_map(self.id.krate); 32 let def_map = self.id.def_map(db.upcast());
33 match def_map[self.id.local_id].origin { 33 match def_map[self.id.local_id].origin {
34 ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs, 34 ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs,
35 _ => false, 35 _ => false,
@@ -39,7 +39,7 @@ impl Module {
39 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. 39 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
40 /// `None` for the crate root. 40 /// `None` for the crate root.
41 pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> { 41 pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> {
42 let def_map = db.crate_def_map(self.id.krate); 42 let def_map = self.id.def_map(db.upcast());
43 def_map[self.id.local_id].declaration_source(db.upcast()) 43 def_map[self.id.local_id].declaration_source(db.upcast())
44 } 44 }
45} 45}
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index ab213e04c..0a30b4f5b 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -814,7 +814,7 @@ impl<'a> SemanticsScope<'a> {
814 } 814 }
815 resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), 815 resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()),
816 resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), 816 resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()),
817 resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(TypeParam { id }), 817 resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(id.into()),
818 resolver::ScopeDef::Local(pat_id) => { 818 resolver::ScopeDef::Local(pat_id) => {
819 let parent = resolver.body_owner().unwrap().into(); 819 let parent = resolver.body_owner().unwrap().into();
820 ScopeDef::Local(Local { parent, pat_id }) 820 ScopeDef::Local(Local { parent, pat_id })
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 9bf60c72a..775f7ec8b 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -31,6 +31,7 @@ impl SourceToDefCtx<'_, '_> {
31 pub(super) fn file_to_def(&mut self, file: FileId) -> Option<ModuleId> { 31 pub(super) fn file_to_def(&mut self, file: FileId) -> Option<ModuleId> {
32 let _p = profile::span("SourceBinder::to_module_def"); 32 let _p = profile::span("SourceBinder::to_module_def");
33 let (krate, local_id) = self.db.relevant_crates(file).iter().find_map(|&crate_id| { 33 let (krate, local_id) = self.db.relevant_crates(file).iter().find_map(|&crate_id| {
34 // FIXME: inner items
34 let crate_def_map = self.db.crate_def_map(crate_id); 35 let crate_def_map = self.db.crate_def_map(crate_id);
35 let local_id = crate_def_map.modules_for_file(file).next()?; 36 let local_id = crate_def_map.modules_for_file(file).next()?;
36 Some((crate_id, local_id)) 37 Some((crate_id, local_id))
@@ -60,7 +61,7 @@ impl SourceToDefCtx<'_, '_> {
60 }?; 61 }?;
61 62
62 let child_name = src.value.name()?.as_name(); 63 let child_name = src.value.name()?.as_name();
63 let def_map = self.db.crate_def_map(parent_module.krate); 64 let def_map = parent_module.def_map(self.db.upcast());
64 let child_id = *def_map[parent_module.local_id].children.get(&child_name)?; 65 let child_id = *def_map[parent_module.local_id].children.get(&child_name)?;
65 Some(ModuleId { krate: parent_module.krate, local_id: child_id }) 66 Some(ModuleId { krate: parent_module.krate, local_id: child_id })
66 } 67 }
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 1b09ff816..6513daec8 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -196,7 +196,7 @@ impl Attrs {
196 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { 196 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
197 let raw_attrs = match def { 197 let raw_attrs = match def {
198 AttrDefId::ModuleId(module) => { 198 AttrDefId::ModuleId(module) => {
199 let def_map = db.crate_def_map(module.krate); 199 let def_map = module.def_map(db);
200 let mod_data = &def_map[module.local_id]; 200 let mod_data = &def_map[module.local_id];
201 match mod_data.declaration_source(db) { 201 match mod_data.declaration_source(db) {
202 Some(it) => { 202 Some(it) => {
@@ -207,6 +207,7 @@ impl Attrs {
207 mod_data.definition_source(db).as_ref().map(|src| match src { 207 mod_data.definition_source(db).as_ref().map(|src| match src {
208 ModuleSource::SourceFile(file) => file as &dyn AttrsOwner, 208 ModuleSource::SourceFile(file) => file as &dyn AttrsOwner,
209 ModuleSource::Module(module) => module as &dyn AttrsOwner, 209 ModuleSource::Module(module) => module as &dyn AttrsOwner,
210 ModuleSource::BlockExpr(block) => block as &dyn AttrsOwner,
210 }), 211 }),
211 ), 212 ),
212 } 213 }
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 344f0b6c0..d0c84ab0b 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -29,7 +29,7 @@ use crate::{
29 expr::{Expr, ExprId, Label, LabelId, Pat, PatId}, 29 expr::{Expr, ExprId, Label, LabelId, Pat, PatId},
30 item_scope::BuiltinShadowMode, 30 item_scope::BuiltinShadowMode,
31 item_scope::ItemScope, 31 item_scope::ItemScope,
32 nameres::CrateDefMap, 32 nameres::DefMap,
33 path::{ModPath, Path}, 33 path::{ModPath, Path},
34 src::HasSource, 34 src::HasSource,
35 AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, 35 AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId,
@@ -45,7 +45,7 @@ pub(crate) struct CfgExpander {
45 45
46pub(crate) struct Expander { 46pub(crate) struct Expander {
47 cfg_expander: CfgExpander, 47 cfg_expander: CfgExpander,
48 crate_def_map: Arc<CrateDefMap>, 48 crate_def_map: Arc<DefMap>,
49 current_file_id: HirFileId, 49 current_file_id: HirFileId,
50 ast_id_map: Arc<AstIdMap>, 50 ast_id_map: Arc<AstIdMap>,
51 module: ModuleId, 51 module: ModuleId,
@@ -86,7 +86,7 @@ impl Expander {
86 module: ModuleId, 86 module: ModuleId,
87 ) -> Expander { 87 ) -> Expander {
88 let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); 88 let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
89 let crate_def_map = db.crate_def_map(module.krate); 89 let crate_def_map = module.def_map(db);
90 let ast_id_map = db.ast_id_map(current_file_id); 90 let ast_id_map = db.ast_id_map(current_file_id);
91 Expander { 91 Expander {
92 cfg_expander, 92 cfg_expander,
@@ -122,7 +122,7 @@ impl Expander {
122 122
123 let mut err = None; 123 let mut err = None;
124 let call_id = 124 let call_id =
125 macro_call.as_call_id_with_errors(db, self.crate_def_map.krate, resolver, &mut |e| { 125 macro_call.as_call_id_with_errors(db, self.crate_def_map.krate(), resolver, &mut |e| {
126 err.get_or_insert(e); 126 err.get_or_insert(e);
127 }); 127 });
128 let call_id = match call_id { 128 let call_id = match call_id {
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index de77d5fc9..2e5d0a01e 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -6,18 +6,24 @@ use crate::{test_db::TestDB, ModuleDefId};
6use super::*; 6use super::*;
7 7
8fn lower(ra_fixture: &str) -> Arc<Body> { 8fn lower(ra_fixture: &str) -> Arc<Body> {
9 let (db, file_id) = crate::test_db::TestDB::with_single_file(ra_fixture); 9 let db = crate::test_db::TestDB::with_files(ra_fixture);
10 10
11 let krate = db.crate_graph().iter().next().unwrap(); 11 let krate = db.crate_graph().iter().next().unwrap();
12 let def_map = db.crate_def_map(krate); 12 let def_map = db.crate_def_map(krate);
13 let module = def_map.modules_for_file(file_id).next().unwrap(); 13 let mut fn_def = None;
14 let module = &def_map[module]; 14 'outer: for (_, module) in def_map.modules() {
15 let fn_def = match module.scope.declarations().next().unwrap() { 15 for decl in module.scope.declarations() {
16 ModuleDefId::FunctionId(it) => it, 16 match decl {
17 _ => panic!(), 17 ModuleDefId::FunctionId(it) => {
18 }; 18 fn_def = Some(it);
19 break 'outer;
20 }
21 _ => {}
22 }
23 }
24 }
19 25
20 db.body(fn_def.into()) 26 db.body(fn_def.unwrap().into())
21} 27}
22 28
23fn check_diagnostics(ra_fixture: &str) { 29fn check_diagnostics(ra_fixture: &str) {
@@ -42,6 +48,25 @@ fn main() { n_nuple!(1,2,3); }
42} 48}
43 49
44#[test] 50#[test]
51fn macro_resolve() {
52 // Regression test for a path resolution bug introduced with inner item handling.
53 lower(
54 r"
55macro_rules! vec {
56 () => { () };
57 ($elem:expr; $n:expr) => { () };
58 ($($x:expr),+ $(,)?) => { () };
59}
60mod m {
61 fn outer() {
62 let _ = vec![FileSet::default(); self.len()];
63 }
64}
65 ",
66 );
67}
68
69#[test]
45fn cfg_diagnostics() { 70fn cfg_diagnostics() {
46 check_diagnostics( 71 check_diagnostics(
47 r" 72 r"
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index dcb00a1d9..65d85c86a 100644
--- a/crates/hir_def/src/child_by_source.rs
+++ b/crates/hir_def/src/child_by_source.rs
@@ -74,7 +74,7 @@ impl ChildBySource for ImplId {
74 74
75impl ChildBySource for ModuleId { 75impl ChildBySource for ModuleId {
76 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { 76 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
77 let crate_def_map = db.crate_def_map(self.krate); 77 let crate_def_map = self.def_map(db);
78 let module_data = &crate_def_map[self.local_id]; 78 let module_data = &crate_def_map[self.local_id];
79 module_data.scope.child_by_source(db) 79 module_data.scope.child_by_source(db)
80 } 80 }
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs
index 6ef9fe790..a87c80b8a 100644
--- a/crates/hir_def/src/db.rs
+++ b/crates/hir_def/src/db.rs
@@ -2,9 +2,9 @@
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use base_db::{salsa, CrateId, SourceDatabase, Upcast}; 4use base_db::{salsa, CrateId, SourceDatabase, Upcast};
5use hir_expand::{db::AstDatabase, HirFileId}; 5use hir_expand::{db::AstDatabase, AstId, HirFileId};
6use la_arena::ArenaMap; 6use la_arena::ArenaMap;
7use syntax::SmolStr; 7use syntax::{ast, SmolStr};
8 8
9use crate::{ 9use crate::{
10 adt::{EnumData, StructData}, 10 adt::{EnumData, StructData},
@@ -15,7 +15,7 @@ use crate::{
15 import_map::ImportMap, 15 import_map::ImportMap,
16 item_tree::ItemTree, 16 item_tree::ItemTree,
17 lang_item::{LangItemTarget, LangItems}, 17 lang_item::{LangItemTarget, LangItems},
18 nameres::CrateDefMap, 18 nameres::DefMap,
19 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, 19 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc,
20 GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId, StaticLoc, StructId, 20 GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId, StaticLoc, StructId,
21 StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId, 21 StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId,
@@ -50,10 +50,13 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
50 50
51 #[salsa::invoke(crate_def_map_wait)] 51 #[salsa::invoke(crate_def_map_wait)]
52 #[salsa::transparent] 52 #[salsa::transparent]
53 fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>; 53 fn crate_def_map(&self, krate: CrateId) -> Arc<DefMap>;
54 54
55 #[salsa::invoke(CrateDefMap::crate_def_map_query)] 55 #[salsa::invoke(DefMap::crate_def_map_query)]
56 fn crate_def_map_query(&self, krate: CrateId) -> Arc<CrateDefMap>; 56 fn crate_def_map_query(&self, krate: CrateId) -> Arc<DefMap>;
57
58 #[salsa::invoke(DefMap::block_def_map_query)]
59 fn block_def_map(&self, krate: CrateId, block: AstId<ast::BlockExpr>) -> Arc<DefMap>;
57 60
58 #[salsa::invoke(StructData::struct_data_query)] 61 #[salsa::invoke(StructData::struct_data_query)]
59 fn struct_data(&self, id: StructId) -> Arc<StructData>; 62 fn struct_data(&self, id: StructId) -> Arc<StructData>;
@@ -112,7 +115,7 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
112 fn import_map(&self, krate: CrateId) -> Arc<ImportMap>; 115 fn import_map(&self, krate: CrateId) -> Arc<ImportMap>;
113} 116}
114 117
115fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { 118fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<DefMap> {
116 let _p = profile::span("crate_def_map:wait"); 119 let _p = profile::span("crate_def_map:wait");
117 db.crate_def_map_query(krate) 120 db.crate_def_map_query(krate)
118} 121}
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index 4a212d291..c01b6daf2 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -4,7 +4,7 @@ use hir_expand::name::{known, AsName, Name};
4use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5use test_utils::mark; 5use test_utils::mark;
6 6
7use crate::nameres::CrateDefMap; 7use crate::nameres::DefMap;
8use crate::{ 8use crate::{
9 db::DefDatabase, 9 db::DefDatabase,
10 item_scope::ItemInNs, 10 item_scope::ItemInNs,
@@ -47,11 +47,11 @@ impl ModPath {
47 } 47 }
48} 48}
49 49
50fn check_self_super(def_map: &CrateDefMap, item: ItemInNs, from: ModuleId) -> Option<ModPath> { 50fn check_self_super(def_map: &DefMap, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
51 if item == ItemInNs::Types(from.into()) { 51 if item == ItemInNs::Types(from.into()) {
52 // - if the item is the module we're in, use `self` 52 // - if the item is the module we're in, use `self`
53 Some(ModPath::from_segments(PathKind::Super(0), Vec::new())) 53 Some(ModPath::from_segments(PathKind::Super(0), Vec::new()))
54 } else if let Some(parent_id) = def_map.modules[from.local_id].parent { 54 } else if let Some(parent_id) = def_map[from.local_id].parent {
55 // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) 55 // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
56 if item 56 if item
57 == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { 57 == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId {
@@ -110,8 +110,8 @@ fn find_path_inner(
110 // Base cases: 110 // Base cases:
111 111
112 // - if the item is already in scope, return the name under which it is 112 // - if the item is already in scope, return the name under which it is
113 let def_map = db.crate_def_map(from.krate); 113 let def_map = from.def_map(db);
114 let from_scope: &crate::item_scope::ItemScope = &def_map.modules[from.local_id].scope; 114 let from_scope: &crate::item_scope::ItemScope = &def_map[from.local_id].scope;
115 let scope_name = 115 let scope_name =
116 if let Some((name, _)) = from_scope.name_of(item) { Some(name.clone()) } else { None }; 116 if let Some((name, _)) = from_scope.name_of(item) { Some(name.clone()) } else { None };
117 if prefixed.is_none() && scope_name.is_some() { 117 if prefixed.is_none() && scope_name.is_some() {
@@ -123,7 +123,7 @@ fn find_path_inner(
123 if item 123 if item
124 == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId { 124 == ItemInNs::Types(ModuleDefId::ModuleId(ModuleId {
125 krate: from.krate, 125 krate: from.krate,
126 local_id: def_map.root, 126 local_id: def_map.root(),
127 })) 127 }))
128 { 128 {
129 return Some(ModPath::from_segments(PathKind::Crate, Vec::new())); 129 return Some(ModPath::from_segments(PathKind::Crate, Vec::new()));
@@ -136,7 +136,7 @@ fn find_path_inner(
136 } 136 }
137 137
138 // - if the item is the crate root of a dependency crate, return the name from the extern prelude 138 // - if the item is the crate root of a dependency crate, return the name from the extern prelude
139 for (name, def_id) in &def_map.extern_prelude { 139 for (name, def_id) in def_map.extern_prelude() {
140 if item == ItemInNs::Types(*def_id) { 140 if item == ItemInNs::Types(*def_id) {
141 let name = scope_name.unwrap_or_else(|| name.clone()); 141 let name = scope_name.unwrap_or_else(|| name.clone());
142 return Some(ModPath::from_segments(PathKind::Plain, vec![name])); 142 return Some(ModPath::from_segments(PathKind::Plain, vec![name]));
@@ -144,10 +144,10 @@ fn find_path_inner(
144 } 144 }
145 145
146 // - if the item is in the prelude, return the name from there 146 // - if the item is in the prelude, return the name from there
147 if let Some(prelude_module) = def_map.prelude { 147 if let Some(prelude_module) = def_map.prelude() {
148 let prelude_def_map = db.crate_def_map(prelude_module.krate); 148 let prelude_def_map = prelude_module.def_map(db);
149 let prelude_scope: &crate::item_scope::ItemScope = 149 let prelude_scope: &crate::item_scope::ItemScope =
150 &prelude_def_map.modules[prelude_module.local_id].scope; 150 &prelude_def_map[prelude_module.local_id].scope;
151 if let Some((name, vis)) = prelude_scope.name_of(item) { 151 if let Some((name, vis)) = prelude_scope.name_of(item) {
152 if vis.is_visible_from(db, from) { 152 if vis.is_visible_from(db, from) {
153 return Some(ModPath::from_segments(PathKind::Plain, vec![name.clone()])); 153 return Some(ModPath::from_segments(PathKind::Plain, vec![name.clone()]));
@@ -175,7 +175,7 @@ fn find_path_inner(
175 175
176 // - otherwise, look for modules containing (reexporting) it and import it from one of those 176 // - otherwise, look for modules containing (reexporting) it and import it from one of those
177 177
178 let crate_root = ModuleId { local_id: def_map.root, krate: from.krate }; 178 let crate_root = ModuleId { local_id: def_map.root(), krate: from.krate };
179 let crate_attrs = db.attrs(crate_root.into()); 179 let crate_attrs = db.attrs(crate_root.into());
180 let prefer_no_std = crate_attrs.by_key("no_std").exists(); 180 let prefer_no_std = crate_attrs.by_key("no_std").exists();
181 let mut best_path = None; 181 let mut best_path = None;
@@ -283,11 +283,11 @@ fn find_local_import_locations(
283 // above `from` with any visibility. That means we do not need to descend into private siblings 283 // above `from` with any visibility. That means we do not need to descend into private siblings
284 // of `from` (and similar). 284 // of `from` (and similar).
285 285
286 let def_map = db.crate_def_map(from.krate); 286 let def_map = from.def_map(db);
287 287
288 // Compute the initial worklist. We start with all direct child modules of `from` as well as all 288 // Compute the initial worklist. We start with all direct child modules of `from` as well as all
289 // of its (recursive) parent modules. 289 // of its (recursive) parent modules.
290 let data = &def_map.modules[from.local_id]; 290 let data = &def_map[from.local_id];
291 let mut worklist = data 291 let mut worklist = data
292 .children 292 .children
293 .values() 293 .values()
@@ -296,7 +296,7 @@ fn find_local_import_locations(
296 let mut parent = data.parent; 296 let mut parent = data.parent;
297 while let Some(p) = parent { 297 while let Some(p) = parent {
298 worklist.push(ModuleId { krate: from.krate, local_id: p }); 298 worklist.push(ModuleId { krate: from.krate, local_id: p });
299 parent = def_map.modules[p].parent; 299 parent = def_map[p].parent;
300 } 300 }
301 301
302 let mut seen: FxHashSet<_> = FxHashSet::default(); 302 let mut seen: FxHashSet<_> = FxHashSet::default();
@@ -312,7 +312,7 @@ fn find_local_import_locations(
312 &def_map[module.local_id] 312 &def_map[module.local_id]
313 } else { 313 } else {
314 // The crate might reexport a module defined in another crate. 314 // The crate might reexport a module defined in another crate.
315 ext_def_map = db.crate_def_map(module.krate); 315 ext_def_map = module.def_map(db);
316 &ext_def_map[module.local_id] 316 &ext_def_map[module.local_id]
317 }; 317 };
318 318
@@ -375,7 +375,7 @@ mod tests {
375 parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap(); 375 parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap();
376 let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap(); 376 let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap();
377 377
378 let crate_def_map = db.crate_def_map(module.krate); 378 let crate_def_map = module.def_map(&db);
379 let resolved = crate_def_map 379 let resolved = crate_def_map
380 .resolve_path( 380 .resolve_path(
381 &db, 381 &db,
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index e5368b293..0b7830445 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -75,7 +75,7 @@ impl ImportMap {
75 75
76 // We look only into modules that are public(ly reexported), starting with the crate root. 76 // We look only into modules that are public(ly reexported), starting with the crate root.
77 let empty = ImportPath { segments: vec![] }; 77 let empty = ImportPath { segments: vec![] };
78 let root = ModuleId { krate, local_id: def_map.root }; 78 let root = ModuleId { krate, local_id: def_map.root() };
79 let mut worklist = vec![(root, empty)]; 79 let mut worklist = vec![(root, empty)];
80 while let Some((module, mod_path)) = worklist.pop() { 80 while let Some((module, mod_path)) = worklist.pop() {
81 let ext_def_map; 81 let ext_def_map;
@@ -83,7 +83,7 @@ impl ImportMap {
83 &def_map[module.local_id] 83 &def_map[module.local_id]
84 } else { 84 } else {
85 // The crate might reexport a module defined in another crate. 85 // The crate might reexport a module defined in another crate.
86 ext_def_map = db.crate_def_map(module.krate); 86 ext_def_map = module.def_map(db);
87 &ext_def_map[module.local_id] 87 &ext_def_map[module.local_id]
88 }; 88 };
89 89
@@ -263,6 +263,7 @@ pub enum ImportKind {
263 Trait, 263 Trait,
264 TypeAlias, 264 TypeAlias,
265 BuiltinType, 265 BuiltinType,
266 AssociatedItem,
266} 267}
267 268
268/// A way to match import map contents against the search query. 269/// A way to match import map contents against the search query.
@@ -282,6 +283,7 @@ pub struct Query {
282 query: String, 283 query: String,
283 lowercased: String, 284 lowercased: String,
284 name_only: bool, 285 name_only: bool,
286 assoc_items_only: bool,
285 search_mode: SearchMode, 287 search_mode: SearchMode,
286 case_sensitive: bool, 288 case_sensitive: bool,
287 limit: usize, 289 limit: usize,
@@ -295,6 +297,7 @@ impl Query {
295 query, 297 query,
296 lowercased, 298 lowercased,
297 name_only: false, 299 name_only: false,
300 assoc_items_only: false,
298 search_mode: SearchMode::Contains, 301 search_mode: SearchMode::Contains,
299 case_sensitive: false, 302 case_sensitive: false,
300 limit: usize::max_value(), 303 limit: usize::max_value(),
@@ -309,6 +312,11 @@ impl Query {
309 Self { name_only: true, ..self } 312 Self { name_only: true, ..self }
310 } 313 }
311 314
315 /// Matches only the entries that are associated items, ignoring the rest.
316 pub fn assoc_items_only(self) -> Self {
317 Self { assoc_items_only: true, ..self }
318 }
319
312 /// Specifies the way to search for the entries using the query. 320 /// Specifies the way to search for the entries using the query.
313 pub fn search_mode(self, search_mode: SearchMode) -> Self { 321 pub fn search_mode(self, search_mode: SearchMode) -> Self {
314 Self { search_mode, ..self } 322 Self { search_mode, ..self }
@@ -331,6 +339,14 @@ impl Query {
331 } 339 }
332 340
333 fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool { 341 fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool {
342 if import.is_trait_assoc_item {
343 if self.exclude_import_kinds.contains(&ImportKind::AssociatedItem) {
344 return false;
345 }
346 } else if self.assoc_items_only {
347 return false;
348 }
349
334 let mut input = if import.is_trait_assoc_item || self.name_only { 350 let mut input = if import.is_trait_assoc_item || self.name_only {
335 import.path.segments.last().unwrap().to_string() 351 import.path.segments.last().unwrap().to_string()
336 } else { 352 } else {
@@ -814,6 +830,56 @@ mod tests {
814 } 830 }
815 831
816 #[test] 832 #[test]
833 fn assoc_items_filtering() {
834 let ra_fixture = r#"
835 //- /main.rs crate:main deps:dep
836 //- /dep.rs crate:dep
837 pub mod fmt {
838 pub trait Display {
839 type FmtTypeAlias;
840 const FMT_CONST: bool;
841
842 fn format_function();
843 fn format_method(&self);
844 }
845 }
846 "#;
847
848 check_search(
849 ra_fixture,
850 "main",
851 Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy).assoc_items_only(),
852 expect![[r#"
853 dep::fmt::Display::FMT_CONST (a)
854 dep::fmt::Display::format_function (a)
855 dep::fmt::Display::format_method (a)
856 "#]],
857 );
858
859 check_search(
860 ra_fixture,
861 "main",
862 Query::new("fmt".to_string())
863 .search_mode(SearchMode::Fuzzy)
864 .exclude_import_kind(ImportKind::AssociatedItem),
865 expect![[r#"
866 dep::fmt (t)
867 dep::fmt::Display (t)
868 "#]],
869 );
870
871 check_search(
872 ra_fixture,
873 "main",
874 Query::new("fmt".to_string())
875 .search_mode(SearchMode::Fuzzy)
876 .assoc_items_only()
877 .exclude_import_kind(ImportKind::AssociatedItem),
878 expect![[r#""#]],
879 );
880 }
881
882 #[test]
817 fn search_mode() { 883 fn search_mode() {
818 let ra_fixture = r#" 884 let ra_fixture = r#"
819 //- /main.rs crate:main deps:dep 885 //- /main.rs crate:main deps:dep
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 9a433b61c..b8d7608e7 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -21,6 +21,7 @@ use hir_expand::{
21 HirFileId, InFile, 21 HirFileId, InFile,
22}; 22};
23use la_arena::{Arena, Idx, RawIdx}; 23use la_arena::{Arena, Idx, RawIdx};
24use profile::Count;
24use rustc_hash::FxHashMap; 25use rustc_hash::FxHashMap;
25use smallvec::SmallVec; 26use smallvec::SmallVec;
26use syntax::{ast, match_ast}; 27use syntax::{ast, match_ast};
@@ -67,15 +68,16 @@ impl GenericParamsId {
67/// The item tree of a source file. 68/// The item tree of a source file.
68#[derive(Debug, Eq, PartialEq)] 69#[derive(Debug, Eq, PartialEq)]
69pub struct ItemTree { 70pub struct ItemTree {
71 _c: Count<Self>,
72
70 top_level: SmallVec<[ModItem; 1]>, 73 top_level: SmallVec<[ModItem; 1]>,
71 attrs: FxHashMap<AttrOwner, RawAttrs>, 74 attrs: FxHashMap<AttrOwner, RawAttrs>,
72 inner_items: FxHashMap<FileAstId<ast::Item>, SmallVec<[ModItem; 1]>>,
73 75
74 data: Option<Box<ItemTreeData>>, 76 data: Option<Box<ItemTreeData>>,
75} 77}
76 78
77impl ItemTree { 79impl ItemTree {
78 pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> { 80 pub