aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/assists/src/handlers/fill_match_arms.rs2
-rw-r--r--crates/assists/src/handlers/fix_visibility.rs27
-rw-r--r--crates/assists/src/utils.rs12
-rw-r--r--crates/completion/src/completions.rs5
-rw-r--r--crates/completion/src/completions/trait_impl.rs47
-rw-r--r--crates/completion/src/render.rs3
-rw-r--r--crates/completion/src/render/const_.rs8
-rw-r--r--crates/completion/src/render/function.rs10
-rw-r--r--crates/completion/src/render/macro_.rs15
-rw-r--r--crates/completion/src/render/type_alias.rs8
-rw-r--r--crates/hir/src/attrs.rs28
-rw-r--r--crates/hir/src/code_model.rs25
-rw-r--r--crates/hir/src/from_id.rs28
-rw-r--r--crates/hir/src/has_source.rs69
-rw-r--r--crates/hir/src/lib.rs5
-rw-r--r--crates/hir_def/src/attr.rs21
-rw-r--r--crates/hir_def/src/lib.rs22
-rw-r--r--crates/ide/src/call_hierarchy.rs8
-rw-r--r--crates/ide/src/diagnostics/fixes.rs9
-rw-r--r--crates/ide/src/display/navigation_target.rs130
-rw-r--r--crates/ide/src/goto_implementation.rs6
-rw-r--r--crates/ide/src/goto_type_definition.rs4
-rw-r--r--crates/ide/src/hover.rs27
-rw-r--r--crates/ide/src/lib.rs5
-rw-r--r--crates/ide/src/view_hir.rs25
-rw-r--r--crates/ide_db/src/search.rs53
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs11
-rw-r--r--crates/rust-analyzer/src/handlers.rs10
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs8
-rw-r--r--crates/rust-analyzer/src/main_loop.rs1
-rw-r--r--docs/dev/README.md2
-rw-r--r--docs/dev/lsp-extensions.md13
-rw-r--r--editors/code/package.json9
-rw-r--r--editors/code/src/commands.ts55
-rw-r--r--editors/code/src/lsp_ext.ts1
-rw-r--r--editors/code/src/main.ts1
36 files changed, 468 insertions, 245 deletions
diff --git a/crates/assists/src/handlers/fill_match_arms.rs b/crates/assists/src/handlers/fill_match_arms.rs
index cb60a3128..f9a62b9fa 100644
--- a/crates/assists/src/handlers/fill_match_arms.rs
+++ b/crates/assists/src/handlers/fill_match_arms.rs
@@ -196,7 +196,7 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::Variant) -> Optio
196 let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?); 196 let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?);
197 197
198 // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though 198 // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though
199 let pat: ast::Pat = match var.source(db).value.kind() { 199 let pat: ast::Pat = match var.source(db)?.value.kind() {
200 ast::StructKind::Tuple(field_list) => { 200 ast::StructKind::Tuple(field_list) => {
201 let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count()); 201 let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count());
202 make::tuple_struct_pat(path, pats).into() 202 make::tuple_struct_pat(path, pats).into()
diff --git a/crates/assists/src/handlers/fix_visibility.rs b/crates/assists/src/handlers/fix_visibility.rs
index 8558a8ff0..de1e8f0bf 100644
--- a/crates/assists/src/handlers/fix_visibility.rs
+++ b/crates/assists/src/handlers/fix_visibility.rs
@@ -97,7 +97,8 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) ->
97 let parent_name = parent.name(ctx.db()); 97 let parent_name = parent.name(ctx.db());
98 let target_module = parent.module(ctx.db()); 98 let target_module = parent.module(ctx.db());
99 99
100 let in_file_source = record_field_def.source(ctx.db()); 100 #[allow(deprecated)]
101 let in_file_source = record_field_def.source(ctx.db())?;
101 let (offset, current_visibility, target) = match in_file_source.value { 102 let (offset, current_visibility, target) = match in_file_source.value {
102 hir::FieldSource::Named(it) => { 103 hir::FieldSource::Named(it) => {
103 let s = it.syntax(); 104 let s = it.syntax();
@@ -145,53 +146,53 @@ fn target_data_for_def(
145 fn offset_target_and_file_id<S, Ast>( 146 fn offset_target_and_file_id<S, Ast>(
146 db: &dyn HirDatabase, 147 db: &dyn HirDatabase,
147 x: S, 148 x: S,
148 ) -> (TextSize, Option<ast::Visibility>, TextRange, FileId) 149 ) -> Option<(TextSize, Option<ast::Visibility>, TextRange, FileId)>
149 where 150 where
150 S: HasSource<Ast = Ast>, 151 S: HasSource<Ast = Ast>,
151 Ast: AstNode + ast::VisibilityOwner, 152 Ast: AstNode + ast::VisibilityOwner,
152 { 153 {
153 let source = x.source(db); 154 let source = x.source(db)?;
154 let in_file_syntax = source.syntax(); 155 let in_file_syntax = source.syntax();
155 let file_id = in_file_syntax.file_id; 156 let file_id = in_file_syntax.file_id;
156 let syntax = in_file_syntax.value; 157 let syntax = in_file_syntax.value;
157 let current_visibility = source.value.visibility(); 158 let current_visibility = source.value.visibility();
158 ( 159 Some((
159 vis_offset(syntax), 160 vis_offset(syntax),
160 current_visibility, 161 current_visibility,
161 syntax.text_range(), 162 syntax.text_range(),
162 file_id.original_file(db.upcast()), 163 file_id.original_file(db.upcast()),
163 ) 164 ))
164 } 165 }
165 166
166 let target_name; 167 let target_name;
167 let (offset, current_visibility, target, target_file) = match def { 168 let (offset, current_visibility, target, target_file) = match def {
168 hir::ModuleDef::Function(f) => { 169 hir::ModuleDef::Function(f) => {
169 target_name = Some(f.name(db)); 170 target_name = Some(f.name(db));
170 offset_target_and_file_id(db, f) 171 offset_target_and_file_id(db, f)?
171 } 172 }
172 hir::ModuleDef::Adt(adt) => { 173 hir::ModuleDef::Adt(adt) => {
173 target_name = Some(adt.name(db)); 174 target_name = Some(adt.name(db));
174 match adt { 175 match adt {
175 hir::Adt::Struct(s) => offset_target_and_file_id(db, s), 176 hir::Adt::Struct(s) => offset_target_and_file_id(db, s)?,
176 hir::Adt::Union(u) => offset_target_and_file_id(db, u), 177 hir::Adt::Union(u) => offset_target_and_file_id(db, u)?,
177 hir::Adt::Enum(e) => offset_target_and_file_id(db, e), 178 hir::Adt::Enum(e) => offset_target_and_file_id(db, e)?,
178 } 179 }
179 } 180 }
180 hir::ModuleDef::Const(c) => { 181 hir::ModuleDef::Const(c) => {
181 target_name = c.name(db); 182 target_name = c.name(db);
182 offset_target_and_file_id(db, c) 183 offset_target_and_file_id(db, c)?
183 } 184 }
184 hir::ModuleDef::Static(s) => { 185 hir::ModuleDef::Static(s) => {
185 target_name = s.name(db); 186 target_name = s.name(db);
186 offset_target_and_file_id(db, s) 187 offset_target_and_file_id(db, s)?
187 } 188 }
188 hir::ModuleDef::Trait(t) => { 189 hir::ModuleDef::Trait(t) => {
189 target_name = Some(t.name(db)); 190 target_name = Some(t.name(db));
190 offset_target_and_file_id(db, t) 191 offset_target_and_file_id(db, t)?
191 } 192 }
192 hir::ModuleDef::TypeAlias(t) => { 193 hir::ModuleDef::TypeAlias(t) => {
193 target_name = Some(t.name(db)); 194 target_name = Some(t.name(db));
194 offset_target_and_file_id(db, t) 195 offset_target_and_file_id(db, t)?
195 } 196 }
196 hir::ModuleDef::Module(m) => { 197 hir::ModuleDef::Module(m) => {
197 target_name = m.name(db); 198 target_name = m.name(db);
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index 5a6125534..b05596446 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -98,10 +98,14 @@ pub fn filter_assoc_items(
98 98
99 items 99 items
100 .iter() 100 .iter()
101 .map(|i| match i { 101 // Note: This throws away items with no source.
102 hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db).value), 102 .filter_map(|i| {
103 hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db).value), 103 let item = match i {
104 hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db).value), 104 hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db)?.value),
105 hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db)?.value),
106 hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db)?.value),
107 };
108 Some(item)
105 }) 109 })
106 .filter(has_def_name) 110 .filter(has_def_name)
107 .filter(|it| match it { 111 .filter(|it| match it {
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs
index d9fe13485..00c9e76f0 100644
--- a/crates/completion/src/completions.rs
+++ b/crates/completion/src/completions.rs
@@ -106,8 +106,9 @@ impl Completions {
106 func: hir::Function, 106 func: hir::Function,
107 local_name: Option<String>, 107 local_name: Option<String>,
108 ) { 108 ) {
109 let item = render_fn(RenderContext::new(ctx), None, local_name, func); 109 if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) {
110 self.add(item) 110 self.add(item)
111 }
111 } 112 }
112 113
113 pub(crate) fn add_variant_pat( 114 pub(crate) fn add_variant_pat(
diff --git a/crates/completion/src/completions/trait_impl.rs b/crates/completion/src/completions/trait_impl.rs
index c4e0d0669..54bb897e9 100644
--- a/crates/completion/src/completions/trait_impl.rs
+++ b/crates/completion/src/completions/trait_impl.rs
@@ -156,19 +156,21 @@ fn add_function_impl(
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
159 let function_decl = function_declaration(&func.source(ctx.db).value); 159 if let Some(src) = func.source(ctx.db) {
160 match ctx.config.snippet_cap { 160 let function_decl = function_declaration(&src.value);
161 Some(cap) => { 161 match ctx.config.snippet_cap {
162 let snippet = format!("{} {{\n $0\n}}", function_decl); 162 Some(cap) => {
163 builder.snippet_edit(cap, TextEdit::replace(range, snippet)) 163 let snippet = format!("{} {{\n $0\n}}", function_decl);
164 } 164 builder.snippet_edit(cap, TextEdit::replace(range, snippet))
165 None => { 165 }
166 let header = format!("{} {{", function_decl); 166 None => {
167 builder.text_edit(TextEdit::replace(range, header)) 167 let header = format!("{} {{", function_decl);
168 builder.text_edit(TextEdit::replace(range, header))
169 }
168 } 170 }
171 .kind(completion_kind)
172 .add_to(acc);
169 } 173 }
170 .kind(completion_kind)
171 .add_to(acc);
172} 174}
173 175
174fn add_type_alias_impl( 176fn add_type_alias_impl(
@@ -200,16 +202,19 @@ fn add_const_impl(
200 let const_name = const_.name(ctx.db).map(|n| n.to_string()); 202 let const_name = const_.name(ctx.db).map(|n| n.to_string());
201 203
202 if let Some(const_name) = const_name { 204 if let Some(const_name) = const_name {
203 let snippet = make_const_compl_syntax(&const_.source(ctx.db).value); 205 if let Some(source) = const_.source(ctx.db) {
204 206 let snippet = make_const_compl_syntax(&source.value);
205 let range = TextRange::new(const_def_node.text_range().start(), ctx.source_range().end()); 207
206 208 let range =
207 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) 209 TextRange::new(const_def_node.text_range().start(), ctx.source_range().end());
208 .text_edit(TextEdit::replace(range, snippet)) 210
209 .lookup_by(const_name) 211 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
210 .kind(CompletionItemKind::Const) 212 .text_edit(TextEdit::replace(range, snippet))
211 .set_documentation(const_.docs(ctx.db)) 213 .lookup_by(const_name)
212 .add_to(acc); 214 .kind(CompletionItemKind::Const)
215 .set_documentation(const_.docs(ctx.db))
216 .add_to(acc);
217 }
213 } 218 }
214} 219}
215 220
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs
index 1ba7201a1..ac0b2a513 100644
--- a/crates/completion/src/render.rs
+++ b/crates/completion/src/render.rs
@@ -157,8 +157,7 @@ impl<'a> Render<'a> {
157 157
158 let kind = match resolution { 158 let kind = match resolution {
159 ScopeDef::ModuleDef(Function(func)) => { 159 ScopeDef::ModuleDef(Function(func)) => {
160 let item = render_fn(self.ctx, import_to_add, Some(local_name), *func); 160 return render_fn(self.ctx, import_to_add, Some(local_name), *func);
161 return Some(item);
162 } 161 }
163 ScopeDef::ModuleDef(Variant(_)) 162 ScopeDef::ModuleDef(Variant(_))
164 if self.ctx.completion.is_pat_binding_or_const 163 if self.ctx.completion.is_pat_binding_or_const
diff --git a/crates/completion/src/render/const_.rs b/crates/completion/src/render/const_.rs
index 039bdabc0..ce924f309 100644
--- a/crates/completion/src/render/const_.rs
+++ b/crates/completion/src/render/const_.rs
@@ -15,7 +15,7 @@ pub(crate) fn render_const<'a>(
15 ctx: RenderContext<'a>, 15 ctx: RenderContext<'a>,
16 const_: hir::Const, 16 const_: hir::Const,
17) -> Option<CompletionItem> { 17) -> Option<CompletionItem> {
18 ConstRender::new(ctx, const_).render() 18 ConstRender::new(ctx, const_)?.render()
19} 19}
20 20
21#[derive(Debug)] 21#[derive(Debug)]
@@ -26,9 +26,9 @@ struct ConstRender<'a> {
26} 26}
27 27
28impl<'a> ConstRender<'a> { 28impl<'a> ConstRender<'a> {
29 fn new(ctx: RenderContext<'a>, const_: hir::Const) -> ConstRender<'a> { 29 fn new(ctx: RenderContext<'a>, const_: hir::Const) -> Option<ConstRender<'a>> {
30 let ast_node = const_.source(ctx.db()).value; 30 let ast_node = const_.source(ctx.db())?.value;
31 ConstRender { ctx, const_, ast_node } 31 Some(ConstRender { ctx, const_, ast_node })
32 } 32 }
33 33
34 fn render(self) -> Option<CompletionItem> { 34 fn render(self) -> Option<CompletionItem> {
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs
index 316e05b52..081be14f4 100644
--- a/crates/completion/src/render/function.rs
+++ b/crates/completion/src/render/function.rs
@@ -14,9 +14,9 @@ pub(crate) fn render_fn<'a>(
14 import_to_add: Option<ImportEdit>, 14 import_to_add: Option<ImportEdit>,
15 local_name: Option<String>, 15 local_name: Option<String>,
16 fn_: hir::Function, 16 fn_: hir::Function,
17) -> CompletionItem { 17) -> Option<CompletionItem> {
18 let _p = profile::span("render_fn"); 18 let _p = profile::span("render_fn");
19 FunctionRender::new(ctx, local_name, fn_).render(import_to_add) 19 Some(FunctionRender::new(ctx, local_name, fn_)?.render(import_to_add))
20} 20}
21 21
22#[derive(Debug)] 22#[derive(Debug)]
@@ -32,11 +32,11 @@ impl<'a> FunctionRender<'a> {
32 ctx: RenderContext<'a>, 32 ctx: RenderContext<'a>,
33 local_name: Option<String>, 33 local_name: Option<String>,
34 fn_: hir::Function, 34 fn_: hir::Function,
35 ) -> FunctionRender<'a> { 35 ) -> Option<FunctionRender<'a>> {
36 let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); 36 let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string());
37 let ast_node = fn_.source(ctx.db()).value; 37 let ast_node = fn_.source(ctx.db())?.value;
38 38
39 FunctionRender { ctx, name, func: fn_, ast_node } 39 Some(FunctionRender { ctx, name, func: fn_, ast_node })
40 } 40 }
41 41
42 fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { 42 fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs
index dac79592f..6f4f9945c 100644
--- a/crates/completion/src/render/macro_.rs
+++ b/crates/completion/src/render/macro_.rs
@@ -39,20 +39,13 @@ impl<'a> MacroRender<'a> {
39 } 39 }
40 40
41 fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> { 41 fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
42 // FIXME: Currently proc-macro do not have ast-node,
43 // such that it does not have source
44 // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913
45 if self.macro_.is_proc_macro() {
46 return None;
47 }
48
49 let mut builder = 42 let mut builder =
50 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label()) 43 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label())
51 .kind(CompletionItemKind::Macro) 44 .kind(CompletionItemKind::Macro)
52 .set_documentation(self.docs.clone()) 45 .set_documentation(self.docs.clone())
53 .set_deprecated(self.ctx.is_deprecated(self.macro_)) 46 .set_deprecated(self.ctx.is_deprecated(self.macro_))
54 .add_import(import_to_add) 47 .add_import(import_to_add)
55 .detail(self.detail()); 48 .set_detail(self.detail());
56 49
57 let needs_bang = self.needs_bang(); 50 let needs_bang = self.needs_bang();
58 builder = match self.ctx.snippet_cap() { 51 builder = match self.ctx.snippet_cap() {
@@ -95,9 +88,9 @@ impl<'a> MacroRender<'a> {
95 format!("{}!", self.name) 88 format!("{}!", self.name)
96 } 89 }
97 90
98 fn detail(&self) -> String { 91 fn detail(&self) -> Option<String> {
99 let ast_node = self.macro_.source(self.ctx.db()).value; 92 let ast_node = self.macro_.source(self.ctx.db())?.value;
100 macro_label(&ast_node) 93 Some(macro_label(&ast_node))
101 } 94 }
102} 95}
103 96
diff --git a/crates/completion/src/render/type_alias.rs b/crates/completion/src/render/type_alias.rs
index 9605c7fa9..69b445b9c 100644
--- a/crates/completion/src/render/type_alias.rs
+++ b/crates/completion/src/render/type_alias.rs
@@ -15,7 +15,7 @@ pub(crate) fn render_type_alias<'a>(
15 ctx: RenderContext<'a>, 15 ctx: RenderContext<'a>,
16 type_alias: hir::TypeAlias, 16 type_alias: hir::TypeAlias,
17) -> Option<CompletionItem> { 17) -> Option<CompletionItem> {
18 TypeAliasRender::new(ctx, type_alias).render() 18 TypeAliasRender::new(ctx, type_alias)?.render()
19} 19}
20 20
21#[derive(Debug)] 21#[derive(Debug)]
@@ -26,9 +26,9 @@ struct TypeAliasRender<'a> {
26} 26}
27 27
28impl<'a> TypeAliasRender<'a> { 28impl<'a> TypeAliasRender<'a> {
29 fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> TypeAliasRender<'a> { 29 fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> Option<TypeAliasRender<'a>> {
30 let ast_node = type_alias.source(ctx.db()).value; 30 let ast_node = type_alias.source(ctx.db())?.value;
31 TypeAliasRender { ctx, type_alias, ast_node } 31 Some(TypeAliasRender { ctx, type_alias, ast_node })
32 } 32 }
33 33
34 fn render(self) -> Option<CompletionItem> { 34 fn render(self) -> Option<CompletionItem> {
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index d32ce37ed..99fb65bac 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -3,15 +3,15 @@ use hir_def::{
3 attr::{Attrs, Documentation}, 3 attr::{Attrs, Documentation},
4 path::ModPath, 4 path::ModPath,
5 resolver::HasResolver, 5 resolver::HasResolver,
6 AttrDefId, ModuleDefId, 6 AttrDefId, GenericParamId, ModuleDefId,
7}; 7};
8use hir_expand::hygiene::Hygiene; 8use hir_expand::hygiene::Hygiene;
9use hir_ty::db::HirDatabase; 9use hir_ty::db::HirDatabase;
10use syntax::ast; 10use syntax::ast;
11 11
12use crate::{ 12use crate::{
13 Adt, Const, Enum, Field, Function, MacroDef, Module, ModuleDef, Static, Struct, Trait, 13 Adt, Const, ConstParam, Enum, Field, Function, GenericParam, LifetimeParam, MacroDef, Module,
14 TypeAlias, Union, Variant, 14 ModuleDef, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
15}; 15};
16 16
17pub trait HasAttrs { 17pub trait HasAttrs {
@@ -62,25 +62,27 @@ impl_has_attrs![
62 (Function, FunctionId), 62 (Function, FunctionId),
63 (Adt, AdtId), 63 (Adt, AdtId),
64 (Module, ModuleId), 64 (Module, ModuleId),
65 (GenericParam, GenericParamId),
65]; 66];
66 67
67macro_rules! impl_has_attrs_adt { 68macro_rules! impl_has_attrs_enum {
68 ($($adt:ident),*) => {$( 69 ($($variant:ident),* for $enum:ident) => {$(
69 impl HasAttrs for $adt { 70 impl HasAttrs for $variant {
70 fn attrs(self, db: &dyn HirDatabase) -> Attrs { 71 fn attrs(self, db: &dyn HirDatabase) -> Attrs {
71 Adt::$adt(self).attrs(db) 72 $enum::$variant(self).attrs(db)
72 } 73 }
73 fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> { 74 fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
74 Adt::$adt(self).docs(db) 75 $enum::$variant(self).docs(db)
75 } 76 }
76 fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<ModuleDef> { 77 fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<ModuleDef> {
77 Adt::$adt(self).resolve_doc_path(db, link, ns) 78 $enum::$variant(self).resolve_doc_path(db, link, ns)
78 } 79 }
79 } 80 }
80 )*}; 81 )*};
81} 82}
82 83
83impl_has_attrs_adt![Struct, Union, Enum]; 84impl_has_attrs_enum![Struct, Union, Enum for Adt];
85impl_has_attrs_enum![TypeParam, ConstParam, LifetimeParam for GenericParam];
84 86
85fn resolve_doc_path( 87fn resolve_doc_path(
86 db: &dyn HirDatabase, 88 db: &dyn HirDatabase,
@@ -99,6 +101,12 @@ fn resolve_doc_path(
99 AttrDefId::TraitId(it) => it.resolver(db.upcast()), 101 AttrDefId::TraitId(it) => it.resolver(db.upcast()),
100 AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()), 102 AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()),
101 AttrDefId::ImplId(it) => it.resolver(db.upcast()), 103 AttrDefId::ImplId(it) => it.resolver(db.upcast()),
104 AttrDefId::GenericParamId(it) => match it {
105 GenericParamId::TypeParamId(it) => it.parent,
106 GenericParamId::LifetimeParamId(it) => it.parent,
107 GenericParamId::ConstParamId(it) => it.parent,
108 }
109 .resolver(db.upcast()),
102 AttrDefId::MacroDefId(_) => return None, 110 AttrDefId::MacroDefId(_) => return None,
103 }; 111 };
104 let path = ast::Path::parse(link).ok()?; 112 let path = ast::Path::parse(link).ok()?;
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index 97b7a8b5f..62eccf475 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -39,7 +39,7 @@ use hir_ty::{
39 TyDefId, TyKind, TypeCtor, 39 TyDefId, TyKind, TypeCtor,
40}; 40};
41use rustc_hash::FxHashSet; 41use rustc_hash::FxHashSet;
42use stdx::impl_from; 42use stdx::{format_to, impl_from};
43use syntax::{ 43use syntax::{
44 ast::{self, AttrsOwner, NameOwner}, 44 ast::{self, AttrsOwner, NameOwner},
45 AstNode, SmolStr, 45 AstNode, SmolStr,
@@ -797,6 +797,19 @@ impl Function {
797 pub fn has_body(self, db: &dyn HirDatabase) -> bool { 797 pub fn has_body(self, db: &dyn HirDatabase) -> bool {
798 db.function_data(self.id).has_body 798 db.function_data(self.id).has_body
799 } 799 }
800
801 /// A textual representation of the HIR of this function for debugging purposes.
802 pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
803 let body = db.body(self.id.into());
804
805 let mut result = String::new();
806 format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db));
807 for (id, expr) in body.exprs.iter() {
808 format_to!(result, "{:?}: {:?}\n", id, expr);
809 }
810
811 result
812 }
800} 813}
801 814
802// Note: logically, this belongs to `hir_ty`, but we are not using it there yet. 815// Note: logically, this belongs to `hir_ty`, but we are not using it there yet.
@@ -983,13 +996,7 @@ impl MacroDef {
983 996
984 /// XXX: this parses the file 997 /// XXX: this parses the file
985 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { 998 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
986 // FIXME: Currently proc-macro do not have ast-node, 999 self.source(db)?.value.name().map(|it| it.as_name())
987 // such that it does not have source
988 // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913
989 if self.is_proc_macro() {
990 return None;
991 }
992 self.source(db).value.name().map(|it| it.as_name())
993 } 1000 }
994 1001
995 /// Indicate it is a proc-macro 1002 /// Indicate it is a proc-macro
@@ -1378,7 +1385,7 @@ impl Impl {
1378 } 1385 }
1379 1386
1380 pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { 1387 pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> {
1381 let src = self.source(db); 1388 let src = self.source(db)?;
1382 let item = src.file_id.is_builtin_derive(db.upcast())?; 1389 let item = src.file_id.is_builtin_derive(db.upcast())?;
1383 let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); 1390 let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id);
1384 1391
diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs
index 2422887e3..3e47a5e9d 100644
--- a/crates/hir/src/from_id.rs
+++ b/crates/hir/src/from_id.rs
@@ -6,13 +6,13 @@
6use hir_def::{ 6use hir_def::{
7 expr::{LabelId, PatId}, 7 expr::{LabelId, PatId},
8 item_scope::ItemInNs, 8 item_scope::ItemInNs,
9 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, ModuleDefId, 9 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, GenericParamId,
10 VariantId, 10 ModuleDefId, VariantId,
11}; 11};
12 12
13use crate::{ 13use crate::{
14 Adt, AssocItem, DefWithBody, Field, GenericDef, Label, Local, MacroDef, ModuleDef, Variant, 14 code_model::GenericParam, Adt, AssocItem, DefWithBody, Field, GenericDef, Label, Local,
15 VariantDef, 15 MacroDef, ModuleDef, Variant, VariantDef,
16}; 16};
17 17
18macro_rules! from_id { 18macro_rules! from_id {
@@ -68,6 +68,26 @@ impl From<Adt> for AdtId {
68 } 68 }
69} 69}
70 70
71impl From<GenericParamId> for GenericParam {
72 fn from(id: GenericParamId) -> Self {
73 match id {
74 GenericParamId::TypeParamId(it) => GenericParam::TypeParam(it.into()),
75 GenericParamId::LifetimeParamId(it) => GenericParam::LifetimeParam(it.into()),
76 GenericParamId::ConstParamId(it) => GenericParam::ConstParam(it.into()),
77 }
78 }
79}
80
81impl From<GenericParam> for GenericParamId {
82 fn from(id: GenericParam) -> Self {
83 match id {
84 GenericParam::TypeParam(it) => GenericParamId::TypeParamId(it.id),
85 GenericParam::LifetimeParam(it) => GenericParamId::LifetimeParamId(it.id),
86 GenericParam::ConstParam(it) => GenericParamId::ConstParamId(it.id),
87 }
88 }
89}
90
71impl From<EnumVariantId> for Variant { 91impl From<EnumVariantId> for Variant {
72 fn from(id: EnumVariantId) -> Self { 92 fn from(id: EnumVariantId) -> Self {
73 Variant { parent: id.parent.into(), id: id.local_id } 93 Variant { parent: id.parent.into(), id: id.local_id }
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index dd7c0c570..7c57d8378 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -16,7 +16,7 @@ use crate::{
16 16
17pub trait HasSource { 17pub trait HasSource {
18 type Ast; 18 type Ast;
19 fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast>; 19 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>>;
20} 20}
21 21
22/// NB: Module is !HasSource, because it has two source nodes at the same time: 22/// NB: Module is !HasSource, because it has two source nodes at the same time:
@@ -46,105 +46,104 @@ impl Module {
46 46
47impl HasSource for Field { 47impl HasSource for Field {
48 type Ast = FieldSource; 48 type Ast = FieldSource;
49 fn source(self, db: &dyn HirDatabase) -> InFile<FieldSource> { 49 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
50 let var = VariantId::from(self.parent); 50 let var = VariantId::from(self.parent);
51 let src = var.child_source(db.upcast()); 51 let src = var.child_source(db.upcast());
52 src.map(|it| match it[self.id].clone() { 52 let field_source = src.map(|it| match it[self.id].clone() {
53 Either::Left(it) => FieldSource::Pos(it), 53 Either::Left(it) => FieldSource::Pos(it),
54 Either::Right(it) => FieldSource::Named(it), 54 Either::Right(it) => FieldSource::Named(it),
55 }) 55 });
56 Some(field_source)
56 } 57 }
57} 58}
58impl HasSource for Struct { 59impl HasSource for Struct {
59 type Ast = ast::Struct; 60 type Ast = ast::Struct;
60 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Struct> { 61 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
61 self.id.lookup(db.upcast()).source(db.upcast()) 62 Some(self.id.lookup(db.upcast()).source(db.upcast()))
62 } 63 }
63} 64}
64impl HasSource for Union { 65impl HasSource for Union {
65 type Ast = ast::Union; 66 type Ast = ast::Union;
66 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Union> { 67 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
67 self.id.lookup(db.upcast()).source(db.upcast()) 68 Some(self.id.lookup(db.upcast()).source(db.upcast()))
68 } 69 }
69} 70}
70impl HasSource for Enum { 71impl HasSource for Enum {
71 type Ast = ast::Enum; 72 type Ast = ast::Enum;
72 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Enum> { 73 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
73 self.id.lookup(db.upcast()).source(db.upcast()) 74 Some(self.id.lookup(db.upcast()).source(db.upcast()))
74 } 75 }
75} 76}
76impl HasSource for Variant { 77impl HasSource for Variant {
77 type Ast = ast::Variant; 78 type Ast = ast::Variant;
78 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Variant> { 79 fn source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Variant>> {
79 self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone()) 80 Some(self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone()))
80 } 81 }
81} 82}
82impl HasSource for Function { 83impl HasSource for Function {
83 type Ast = ast::Fn; 84 type Ast = ast::Fn;
84 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Fn> { 85 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
85 self.id.lookup(db.upcast()).source(db.upcast()) 86 Some(self.id.lookup(db.upcast()).source(db.upcast()))
86 } 87 }
87} 88}
88impl HasSource for Const { 89impl HasSource for Const {
89 type Ast = ast::Const; 90 type Ast = ast::Const;
90 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Const> { 91 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
91 self.id.lookup(db.upcast()).source(db.upcast()) 92 Some(self.id.lookup(db.upcast()).source(db.upcast()))
92 } 93 }
93} 94}
94impl HasSource for Static { 95impl HasSource for Static {
95 type Ast = ast::Static; 96 type Ast = ast::Static;
96 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Static> { 97 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
97 self.id.lookup(db.upcast()).source(db.upcast()) 98 Some(self.id.lookup(db.upcast()).source(db.upcast()))
98 } 99 }
99} 100}
100impl HasSource for Trait { 101impl HasSource for Trait {
101 type Ast = ast::Trait; 102 type Ast = ast::Trait;
102 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Trait> { 103 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
103 self.id.lookup(db.upcast()).source(db.upcast()) 104 Some(self.id.lookup(db.upcast()).source(db.upcast()))
104 } 105 }
105} 106}
106impl HasSource for TypeAlias { 107impl HasSource for TypeAlias {
107 type Ast = ast::TypeAlias; 108 type Ast = ast::TypeAlias;
108 fn source(self, db: &dyn HirDatabase) -> InFile<ast::TypeAlias> { 109 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
109 self.id.lookup(db.upcast()).source(db.upcast()) 110 Some(self.id.lookup(db.upcast()).source(db.upcast()))
110 } 111 }
111} 112}
112impl HasSource for MacroDef { 113impl HasSource for MacroDef {
113 type Ast = ast::Macro; 114 type Ast = ast::Macro;
114 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Macro> { 115 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
115 InFile { 116 let ast_id = self.id.ast_id?;
116 file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id, 117 Some(InFile { file_id: ast_id.file_id, value: ast_id.to_node(db.upcast()) })
117 value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),
118 }
119 } 118 }
120} 119}
121impl HasSource for Impl { 120impl HasSource for Impl {
122 type Ast = ast::Impl; 121 type Ast = ast::Impl;
123 fn source(self, db: &dyn HirDatabase) -> InFile<ast::Impl> { 122 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
124 self.id.lookup(db.upcast()).source(db.upcast()) 123 Some(self.id.lookup(db.upcast()).source(db.upcast()))
125 } 124 }
126} 125}
127 126
128impl HasSource for TypeParam { 127impl HasSource for TypeParam {
129 type Ast = Either<ast::Trait, ast::TypeParam>; 128 type Ast = Either<ast::Trait, ast::TypeParam>;
130 fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> { 129 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
131 let child_source = self.id.parent.child_source(db.upcast()); 130 let child_source = self.id.parent.child_source(db.upcast());
132 child_source.map(|it| it[self.id.local_id].clone()) 131 Some(child_source.map(|it| it[self.id.local_id].clone()))
133 } 132 }
134} 133}
135 134
136impl HasSource for LifetimeParam { 135impl HasSource for LifetimeParam {
137 type Ast = ast::LifetimeParam; 136 type Ast = ast::LifetimeParam;
138 fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> { 137 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
139 let child_source = self.id.parent.child_source(db.upcast()); 138 let child_source = self.id.parent.child_source(db.upcast());
140 child_source.map(|it| it[self.id.local_id].clone()) 139 Some(child_source.map(|it| it[self.id.local_id].clone()))
141 } 140 }
142} 141}
143 142
144impl HasSource for ConstParam { 143impl HasSource for ConstParam {
145 type Ast = ast::ConstParam; 144 type Ast = ast::ConstParam;
146 fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> { 145 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
147 let child_source = self.id.parent.child_source(db.upcast()); 146 let child_source = self.id.parent.child_source(db.upcast());
148 child_source.map(|it| it[self.id.local_id].clone()) 147 Some(child_source.map(|it| it[self.id.local_id].clone()))
149 } 148 }
150} 149}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 8ac27e2dd..769945c47 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -35,8 +35,9 @@ pub use crate::{
35 code_model::{ 35 code_model::{
36 Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const, 36 Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const,
37 ConstParam, Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function, 37 ConstParam, Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function,
38 GenericDef, HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, 38 GenericDef, GenericParam, HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef,
39 ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, 39 Module, ModuleDef, ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union,
40 Variant, VariantDef,
40 }, 41 },
41 has_source::HasSource, 42 has_source::HasSource,
42 semantics::{PathResolution, Semantics, SemanticsScope}, 43 semantics::{PathResolution, Semantics, SemanticsScope},
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index fcf638e0f..6b79e7bad 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -21,7 +21,7 @@ use crate::{
21 nameres::ModuleSource, 21 nameres::ModuleSource,
22 path::{ModPath, PathKind}, 22 path::{ModPath, PathKind},
23 src::HasChildSource, 23 src::HasChildSource,
24 AdtId, AttrDefId, Lookup, 24 AdtId, AttrDefId, GenericParamId, Lookup,
25}; 25};
26 26
27/// Holds documentation 27/// Holds documentation
@@ -235,6 +235,25 @@ impl Attrs {
235 AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), 235 AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
236 AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), 236 AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
237 AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), 237 AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
238 AttrDefId::GenericParamId(it) => match it {
239 GenericParamId::TypeParamId(it) => {
240 let src = it.parent.child_source(db);
241 RawAttrs::from_attrs_owner(
242 db,
243 src.with_value(
244 src.value[it.local_id].as_ref().either(|it| it as _, |it| it as _),
245 ),
246 )
247 }
248 GenericParamId::LifetimeParamId(it) => {
249 let src = it.parent.child_source(db);
250 RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
251 }
252 GenericParamId::ConstParamId(it) => {
253 let src = it.parent.child_source(db);
254 RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
255 }
256 },
238 }; 257 };
239 258
240 raw_attrs.filter(db, def.krate(db)) 259 raw_attrs.filter(db, def.krate(db))
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 25f460504..211cb2faf 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -261,6 +261,15 @@ pub enum AdtId {
261} 261}
262impl_from!(StructId, UnionId, EnumId for AdtId); 262impl_from!(StructId, UnionId, EnumId for AdtId);
263 263
264/// A generic param
265#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
266pub enum GenericParamId {
267 TypeParamId(TypeParamId),
268 LifetimeParamId(LifetimeParamId),
269 ConstParamId(ConstParamId),
270}
271impl_from!(TypeParamId, LifetimeParamId, ConstParamId for GenericParamId);
272
264/// The defs which can be visible in the module. 273/// The defs which can be visible in the module.
265#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 274#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
266pub enum ModuleDefId { 275pub enum ModuleDefId {
@@ -357,6 +366,7 @@ pub enum AttrDefId {
357 TypeAliasId(TypeAliasId), 366 TypeAliasId(TypeAliasId),
358 MacroDefId(MacroDefId), 367 MacroDefId(MacroDefId),
359 ImplId(ImplId), 368 ImplId(ImplId),
369 GenericParamId(GenericParamId),
360} 370}
361 371
362impl_from!( 372impl_from!(
@@ -370,7 +380,8 @@ impl_from!(
370 TraitId, 380 TraitId,
371 TypeAliasId, 381 TypeAliasId,
372 MacroDefId, 382 MacroDefId,
373 ImplId 383 ImplId,
384 GenericParamId
374 for AttrDefId 385 for AttrDefId
375); 386);
376 387
@@ -495,6 +506,15 @@ impl AttrDefId {
495 AttrDefId::TraitId(it) => it.lookup(db).container.module(db).krate, 506 AttrDefId::TraitId(it) => it.lookup(db).container.module(db).krate,
496 AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate, 507 AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate,
497 AttrDefId::ImplId(it) => it.lookup(db).container.module(db).krate, 508 AttrDefId::ImplId(it) => it.lookup(db).container.module(db).krate,
509 AttrDefId::GenericParamId(it) => {
510 match it {
511 GenericParamId::TypeParamId(it) => it.parent,
512 GenericParamId::LifetimeParamId(it) => it.parent,
513 GenericParamId::ConstParamId(it) => it.parent,
514 }
515 .module(db)
516 .krate
517 }
498 // FIXME: `MacroDefId` should store the defining module, then this can implement 518 // FIXME: `MacroDefId` should store the defining module, then this can implement
499 // `HasModule` 519 // `HasModule`
500 AttrDefId::MacroDefId(it) => it.krate, 520 AttrDefId::MacroDefId(it) => it.krate,
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs
index 60e0cd4ad..3c2d39f5d 100644
--- a/crates/ide/src/call_hierarchy.rs
+++ b/crates/ide/src/call_hierarchy.rs
@@ -8,7 +8,7 @@ use ide_db::RootDatabase;
8use syntax::{ast, match_ast, AstNode, TextRange}; 8use syntax::{ast, match_ast, AstNode, TextRange};
9 9
10use crate::{ 10use crate::{
11 display::ToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo, 11 display::TryToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo,
12}; 12};
13 13
14#[derive(Debug, Clone)] 14#[derive(Debug, Clone)]
@@ -61,7 +61,7 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio
61 match node { 61 match node {
62 ast::Fn(it) => { 62 ast::Fn(it) => {
63 let def = sema.to_def(&it)?; 63 let def = sema.to_def(&it)?;
64 Some(def.to_nav(sema.db)) 64 def.try_to_nav(sema.db)
65 }, 65 },
66 _ => None, 66 _ => None,
67 } 67 }
@@ -99,7 +99,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
99 match callable.kind() { 99 match callable.kind() {
100 hir::CallableKind::Function(it) => { 100 hir::CallableKind::Function(it) => {
101 let fn_def: hir::Function = it.into(); 101 let fn_def: hir::Function = it.into();
102 let nav = fn_def.to_nav(db); 102 let nav = fn_def.try_to_nav(db)?;
103 Some(nav) 103 Some(nav)
104 } 104 }
105 _ => None, 105 _ => None,
@@ -107,7 +107,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
107 } 107 }
108 FnCallNode::MethodCallExpr(expr) => { 108 FnCallNode::MethodCallExpr(expr) => {
109 let function = sema.resolve_method_call(&expr)?; 109 let function = sema.resolve_method_call(&expr)?;
110 Some(function.to_nav(db)) 110 function.try_to_nav(db)
111 } 111 }
112 } { 112 } {
113 Some((func_target, name_ref.syntax().text_range())) 113 Some((func_target, name_ref.syntax().text_range()))
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index d79f5c170..ec0f840e9 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -156,20 +156,23 @@ fn missing_record_expr_field_fix(
156 let record_fields = match VariantDef::from(def_id) { 156 let record_fields = match VariantDef::from(def_id) {
157 VariantDef::Struct(s) => { 157 VariantDef::Struct(s) => {
158 module = s.module(sema.db); 158 module = s.module(sema.db);
159 let source = s.source(sema.db); 159 #[allow(deprecated)]
160 let source = s.source(sema.db)?;
160 def_file_id = source.file_id; 161 def_file_id = source.file_id;
161 let fields = source.value.field_list()?; 162 let fields = source.value.field_list()?;
162 record_field_list(fields)? 163 record_field_list(fields)?
163 } 164 }
164 VariantDef::Union(u) => { 165 VariantDef::Union(u) => {
165 module = u.module(sema.db); 166 module = u.module(sema.db);
166 let source = u.source(sema.db); 167 #[allow(deprecated)]
168 let source = u.source(sema.db)?;
167 def_file_id = source.file_id; 169 def_file_id = source.file_id;
168 source.value.record_field_list()? 170 source.value.record_field_list()?
169 } 171 }
170 VariantDef::Variant(e) => { 172 VariantDef::Variant(e) => {
171 module = e.module(sema.db); 173 module = e.module(sema.db);
172 let source = e.source(sema.db); 174 #[allow(deprecated)]
175 let source = e.source(sema.db)?;
173 def_file_id = source.file_id; 176 def_file_id = source.file_id;
174 let fields = source.value.field_list()?; 177 let fields = source.value.field_list()?;
175 record_field_list(fields)? 178 record_field_list(fields)?
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index bcde2b6f1..e24c78301 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -210,41 +210,32 @@ impl ToNav for FileSymbol {
210impl TryToNav for Definition { 210impl TryToNav for Definition {
211 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { 211 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
212 match self { 212 match self {
213 Definition::Macro(it) => { 213 Definition::Macro(it) => it.try_to_nav(db),
214 // FIXME: Currently proc-macro do not have ast-node, 214 Definition::Field(it) => it.try_to_nav(db),
215 // such that it does not have source
216 // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913
217 if it.is_proc_macro() {
218 return None;
219 }
220 Some(it.to_nav(db))
221 }
222 Definition::Field(it) => Some(it.to_nav(db)),
223 Definition::ModuleDef(it) => it.try_to_nav(db), 215 Definition::ModuleDef(it) => it.try_to_nav(db),
224 Definition::SelfType(it) => Some(it.to_nav(db)), 216 Definition::SelfType(it) => it.try_to_nav(db),
225 Definition::Local(it) => Some(it.to_nav(db)), 217 Definition::Local(it) => Some(it.to_nav(db)),
226 Definition::TypeParam(it) => Some(it.to_nav(db)), 218 Definition::TypeParam(it) => it.try_to_nav(db),
227 Definition::LifetimeParam(it) => Some(it.to_nav(db)), 219 Definition::LifetimeParam(it) => it.try_to_nav(db),
228 Definition::Label(it) => Some(it.to_nav(db)), 220 Definition::Label(it) => Some(it.to_nav(db)),
229 Definition::ConstParam(it) => Some(it.to_nav(db)), 221 Definition::ConstParam(it) => it.try_to_nav(db),
230 } 222 }
231 } 223 }
232} 224}
233 225
234impl TryToNav for hir::ModuleDef { 226impl TryToNav for hir::ModuleDef {
235 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { 227 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
236 let res = match self { 228 match self {
237 hir::ModuleDef::Module(it) => it.to_nav(db), 229 hir::ModuleDef::Module(it) => Some(it.to_nav(db)),
238 hir::ModuleDef::Function(it) => it.to_nav(db), 230 hir::ModuleDef::Function(it) => it.try_to_nav(db),
239 hir::ModuleDef::Adt(it) => it.to_nav(db), 231 hir::ModuleDef::Adt(it) => it.try_to_nav(db),
240 hir::ModuleDef::Variant(it) => it.to_nav(db), 232 hir::ModuleDef::Variant(it) => it.try_to_nav(db),
241 hir::ModuleDef::Const(it) => it.to_nav(db), 233 hir::ModuleDef::Const(it) => it.try_to_nav(db),
242 hir::ModuleDef::Static(it) => it.to_nav(db), 234 hir::ModuleDef::Static(it) => it.try_to_nav(db),
243 hir::ModuleDef::Trait(it) => it.to_nav(db), 235 hir::ModuleDef::Trait(it) => it.try_to_nav(db),
244 hir::ModuleDef::TypeAlias(it) => it.to_nav(db), 236 hir::ModuleDef::TypeAlias(it) => it.try_to_nav(db),
245 hir::ModuleDef::BuiltinType(_) => return None, 237 hir::ModuleDef::BuiltinType(_) => None,
246 }; 238 }
247 Some(res)
248 } 239 }
249} 240}
250 241
@@ -279,13 +270,13 @@ impl ToNavFromAst for hir::Trait {
279 const KIND: SymbolKind = SymbolKind::Trait; 270 const KIND: SymbolKind = SymbolKind::Trait;
280} 271}
281 272
282impl<D> ToNav for D 273impl<D> TryToNav for D
283where 274where
284 D: HasSource + ToNavFromAst + Copy + HasAttrs, 275 D: HasSource + ToNavFromAst + Copy + HasAttrs,
285 D::Ast: ast::NameOwner + ShortLabel, 276 D::Ast: ast::NameOwner + ShortLabel,
286{ 277{
287 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 278 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
288 let src = self.source(db); 279 let src = self.source(db)?;
289 let mut res = NavigationTarget::from_named( 280 let mut res = NavigationTarget::from_named(
290 db, 281 db,
291 src.as_ref().map(|it| it as &dyn ast::NameOwner), 282 src.as_ref().map(|it| it as &dyn ast::NameOwner),
@@ -293,7 +284,7 @@ where
293 ); 284 );
294 res.docs = self.docs(db); 285 res.docs = self.docs(db);
295 res.description = src.value.short_label(); 286 res.description = src.value.short_label();
296 res 287 Some(res)
297 } 288 }
298} 289}
299 290
@@ -312,9 +303,9 @@ impl ToNav for hir::Module {
312 } 303 }
313} 304}
314 305
315impl ToNav for hir::Impl { 306impl TryToNav for hir::Impl {
316 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 307 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
317 let src = self.source(db); 308 let src = self.source(db)?;
318 let derive_attr = self.is_builtin_derive(db); 309 let derive_attr = self.is_builtin_derive(db);
319 let frange = if let Some(item) = &derive_attr { 310 let frange = if let Some(item) = &derive_attr {
320 item.syntax().original_file_range(db) 311 item.syntax().original_file_range(db)
@@ -327,21 +318,21 @@ impl ToNav for hir::Impl {
327 src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range) 318 src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range)
328 }; 319 };
329 320
330 NavigationTarget::from_syntax( 321 Some(NavigationTarget::from_syntax(
331 frange.file_id, 322 frange.file_id,
332 "impl".into(), 323 "impl".into(),
333 focus_range, 324 focus_range,
334 frange.range, 325 frange.range,
335 SymbolKind::Impl, 326 SymbolKind::Impl,
336 ) 327 ))
337 } 328 }
338} 329}
339 330
340impl ToNav for hir::Field { 331impl TryToNav for hir::Field {
341 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 332 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
342 let src = self.source(db); 333 let src = self.source(db)?;
343 334
344 match &src.value { 335 let field_source = match &src.value {
345 FieldSource::Named(it) => { 336 FieldSource::Named(it) => {
346 let mut res = 337 let mut res =
347 NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field); 338 NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field);
@@ -359,13 +350,14 @@ impl ToNav for hir::Field {
359 SymbolKind::Field, 350 SymbolKind::Field,
360 ) 351 )
361 } 352 }
362 } 353 };
354 Some(field_source)
363 } 355 }
364} 356}
365 357
366impl ToNav for hir::MacroDef { 358impl TryToNav for hir::MacroDef {
367 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 359 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
368 let src = self.source(db); 360 let src = self.source(db)?;
369 log::debug!("nav target {:#?}", src.value.syntax()); 361 log::debug!("nav target {:#?}", src.value.syntax());
370 let mut res = NavigationTarget::from_named( 362 let mut res = NavigationTarget::from_named(
371 db, 363 db,
@@ -373,26 +365,26 @@ impl ToNav for hir::MacroDef {
373 SymbolKind::Macro, 365 SymbolKind::Macro,
374 ); 366 );
375 res.docs = self.docs(db); 367 res.docs = self.docs(db);
376 res 368 Some(res)
377 } 369 }
378} 370}
379 371
380impl ToNav for hir::Adt { 372impl TryToNav for hir::Adt {
381 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 373 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
382 match self { 374 match self {
383 hir::Adt::Struct(it) => it.to_nav(db), 375 hir::Adt::Struct(it) => it.try_to_nav(db),
384 hir::Adt::Union(it) => it.to_nav(db), 376 hir::Adt::Union(it) => it.try_to_nav(db),
385 hir::Adt::Enum(it) => it.to_nav(db), 377 hir::Adt::Enum(it) => it.try_to_nav(db),
386 } 378 }
387 } 379 }
388} 380}
389 381
390impl ToNav for hir::AssocItem { 382impl TryToNav for hir::AssocItem {
391 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 383 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
392 match self { 384 match self {
393 AssocItem::Function(it) => it.to_nav(db), 385 AssocItem::Function(it) => it.try_to_nav(db),
394 AssocItem::Const(it) => it.to_nav(db), 386 AssocItem::Const(it) => it.try_to_nav(db),
395 AssocItem::TypeAlias(it) => it.to_nav(db), 387 AssocItem::TypeAlias(it) => it.try_to_nav(db),
396 } 388 }
397 } 389 }
398} 390}
@@ -446,9 +438,9 @@ impl ToNav for hir::Label {
446 } 438 }
447} 439}
448 440
449impl ToNav for hir::TypeParam { 441impl TryToNav for hir::TypeParam {
450 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 442 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
451 let src = self.source(db); 443 let src = self.source(db)?;
452 let full_range = match &src.value { 444 let full_range = match &src.value {
453 Either::Left(it) => it.syntax().text_range(), 445 Either::Left(it) => it.syntax().text_range(),
454 Either::Right(it) => it.syntax().text_range(), 446 Either::Right(it) => it.syntax().text_range(),
@@ -457,7 +449,7 @@ impl ToNav for hir::TypeParam {
457 Either::Left(_) => None, 449 Either::Left(_) => None,
458 Either::Right(it) => it.name().map(|it| it.syntax().text_range()), 450 Either::Right(it) => it.name().map(|it| it.syntax().text_range()),
459 }; 451 };
460 NavigationTarget { 452 Some(NavigationTarget {
461 file_id: src.file_id.original_file(db), 453 file_id: src.file_id.original_file(db),
462 name: self.name(db).to_string().into(), 454 name: self.name(db).to_string().into(),
463 kind: Some(SymbolKind::TypeParam), 455 kind: Some(SymbolKind::TypeParam),
@@ -466,15 +458,15 @@ impl ToNav for hir::TypeParam {
466 container_name: None, 458 container_name: None,
467 description: None, 459 description: None,
468 docs: None, 460 docs: None,
469 } 461 })
470 } 462 }
471} 463}
472 464
473impl ToNav for hir::LifetimeParam { 465impl TryToNav for hir::LifetimeParam {
474 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 466 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
475 let src = self.source(db); 467 let src = self.source(db)?;
476 let full_range = src.value.syntax().text_range(); 468 let full_range = src.value.syntax().text_range();
477 NavigationTarget { 469 Some(NavigationTarget {
478 file_id: src.file_id.original_file(db), 470 file_id: src.file_id.original_file(db),
479 name: self.name(db).to_string().into(), 471 name: self.name(db).to_string().into(),
480 kind: Some(SymbolKind::LifetimeParam), 472 kind: Some(SymbolKind::LifetimeParam),
@@ -483,15 +475,15 @@ impl ToNav for hir::LifetimeParam {
483 container_name: None, 475 container_name: None,
484 description: None, 476 description: None,
485 docs: None, 477 docs: None,
486 } 478 })
487 } 479 }
488} 480}
489 481
490impl ToNav for hir::ConstParam { 482impl TryToNav for hir::ConstParam {
491 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 483 fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
492 let src = self.source(db); 484 let src = self.source(db)?;
493 let full_range = src.value.syntax().text_range(); 485 let full_range = src.value.syntax().text_range();
494 NavigationTarget { 486 Some(NavigationTarget {
495 file_id: src.file_id.original_file(db), 487 file_id: src.file_id.original_file(db),
496 name: self.name(db).to_string().into(), 488 name: self.name(db).to_string().into(),
497 kind: Some(SymbolKind::ConstParam), 489 kind: Some(SymbolKind::ConstParam),
@@ -500,7 +492,7 @@ impl ToNav for hir::ConstParam {
500 container_name: None, 492 container_name: None,
501 description: None, 493 description: None,
502 docs: None, 494 docs: None,
503 } 495 })
504 } 496 }
505} 497}
506 498
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index 6eac39639..da9378a97 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -2,7 +2,7 @@ use hir::{Crate, Impl, Semantics};
2use ide_db::RootDatabase; 2use ide_db::RootDatabase;
3use syntax::{algo::find_node_at_offset, ast, AstNode}; 3use syntax::{algo::find_node_at_offset, ast, AstNode};
4 4
5use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; 5use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
6 6
7// Feature: Go to Implementation 7// Feature: Go to Implementation
8// 8//
@@ -55,7 +55,7 @@ fn impls_for_def(
55 impls 55 impls
56 .into_iter() 56 .into_iter()
57 .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db))) 57 .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db)))
58 .map(|imp| imp.to_nav(sema.db)) 58 .filter_map(|imp| imp.try_to_nav(sema.db))
59 .collect(), 59 .collect(),
60 ) 60 )
61} 61}
@@ -69,7 +69,7 @@ fn impls_for_trait(
69 69
70 let impls = Impl::for_trait(sema.db, krate, tr); 70 let impls = Impl::for_trait(sema.db, krate, tr);
71 71
72 Some(impls.into_iter().map(|imp| imp.to_nav(sema.db)).collect()) 72 Some(impls.into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect())
73} 73}
74 74
75#[cfg(test)] 75#[cfg(test)]
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs
index aba6bf5dc..7e84e06be 100644
--- a/crates/ide/src/goto_type_definition.rs
+++ b/crates/ide/src/goto_type_definition.rs
@@ -1,7 +1,7 @@
1use ide_db::RootDatabase; 1use ide_db::RootDatabase;
2use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; 2use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
3 3
4use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; 4use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
5 5
6// Feature: Go to Type Definition 6// Feature: Go to Type Definition
7// 7//
@@ -37,7 +37,7 @@ pub(crate) fn goto_type_definition(
37 37
38 let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?; 38 let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?;
39 39
40 let nav = adt_def.to_nav(db); 40 let nav = adt_def.try_to_nav(db)?;
41 Some(RangeInfo::new(node.text_range(), vec![nav])) 41 Some(RangeInfo::new(node.text_range(), vec![nav]))
42} 42}
43 43
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 98c7bfbe5..2737c900f 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -13,7 +13,7 @@ use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset,
13use test_utils::mark; 13use test_utils::mark;
14 14
15use crate::{ 15use crate::{
16 display::{macro_label, ShortLabel, ToNav, TryToNav}, 16 display::{macro_label, ShortLabel, TryToNav},
17 doc_links::{remove_links, rewrite_links}, 17 doc_links::{remove_links, rewrite_links},
18 markdown_remove::remove_markdown, 18 markdown_remove::remove_markdown,
19 markup::Markup, 19 markup::Markup,
@@ -183,10 +183,10 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
183 183
184 match def { 184 match def {
185 Definition::ModuleDef(it) => match it { 185 Definition::ModuleDef(it) => match it {
186 ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))), 186 ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.try_to_nav(db)?)),
187 ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))), 187 ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.try_to_nav(db)?)),
188 ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))), 188 ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.try_to_nav(db)?)),
189 ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))), 189 ModuleDef::Trait(it) => Some(to_action(it.try_to_nav(db)?)),
190 _ => None, 190 _ => None,
191 }, 191 },
192 _ => None, 192 _ => None,
@@ -206,7 +206,8 @@ fn runnable_action(
206 _ => None, 206 _ => None,
207 }, 207 },
208 ModuleDef::Function(it) => { 208 ModuleDef::Function(it) => {
209 let src = it.source(sema.db); 209 #[allow(deprecated)]
210 let src = it.source(sema.db)?;
210 if src.file_id != file_id.into() { 211 if src.file_id != file_id.into() {
211 mark::hit!(hover_macro_generated_struct_fn_doc_comment); 212 mark::hit!(hover_macro_generated_struct_fn_doc_comment);
212 mark::hit!(hover_macro_generated_struct_fn_doc_attr); 213 mark::hit!(hover_macro_generated_struct_fn_doc_attr);
@@ -326,17 +327,12 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
326 let mod_path = definition_mod_path(db, &def); 327 let mod_path = definition_mod_path(db, &def);
327 return match def { 328 return match def {
328 Definition::Macro(it) => { 329 Definition::Macro(it) => {
329 // FIXME: Currently proc-macro do not have ast-node, 330 let label = macro_label(&it.source(db)?.value);
330 // such that it does not have source
331 // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913
332 if it.is_proc_macro() {
333 return None;
334 }
335 let label = macro_label(&it.source(db).value);
336 from_def_source_labeled(db, it, Some(label), mod_path) 331 from_def_source_labeled(db, it, Some(label), mod_path)
337 } 332 }
338 Definition::Field(def) => { 333 Definition::Field(def) => {
339 let src = def.source(db).value; 334 #[allow(deprecated)]
335 let src = def.source(db)?.value;
340 if let FieldSource::Named(it) = src { 336 if let FieldSource::Named(it) = src {
341 from_def_source_labeled(db, def, it.short_label(), mod_path) 337 from_def_source_labeled(db, def, it.short_label(), mod_path)
342 } else { 338 } else {
@@ -385,7 +381,8 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
385 D: HasSource<Ast = A> + HasAttrs + Copy, 381 D: HasSource<Ast = A> + HasAttrs + Copy,
386 A: ShortLabel, 382 A: ShortLabel,
387 { 383 {
388 let short_label = def.source(db).value.short_label(); 384 #[allow(deprecated)]
385 let short_label = def.source(db)?.value.short_label();
389 from_def_source_labeled(db, def, short_label, mod_path) 386 from_def_source_labeled(db, def, short_label, mod_path)
390 } 387 }
391 388
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index b3331f03f..a450794f3 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -31,6 +31,7 @@ mod folding_ranges;
31mod goto_definition; 31mod goto_definition;
32mod goto_implementation; 32mod goto_implementation;
33mod goto_type_definition; 33mod goto_type_definition;
34mod view_hir;
34mod hover; 35mod hover;
35mod inlay_hints; 36mod inlay_hints;
36mod join_lines; 37mod join_lines;
@@ -271,6 +272,10 @@ impl Analysis {
271 self.with_db(|db| syntax_tree::syntax_tree(&db, file_id, text_range)) 272 self.with_db(|db| syntax_tree::syntax_tree(&db, file_id, text_range))
272 } 273 }
273 274
275 pub fn view_hir(&self, position: FilePosition) -> Cancelable<String> {
276 self.with_db(|db| view_hir::view_hir(&db, position))
277 }
278
274 pub fn expand_macro(&self, position: FilePosition) -> Cancelable<Option<ExpandedMacro>> { 279 pub fn expand_macro(&self, position: FilePosition) -> Cancelable<Option<ExpandedMacro>> {
275 self.with_db(|db| expand_macro::expand_macro(db, position)) 280 self.with_db(|db| expand_macro::expand_macro(db, position))
276 } 281 }
diff --git a/crates/ide/src/view_hir.rs b/crates/ide/src/view_hir.rs
new file mode 100644
index 000000000..cfcfb7cfb
--- /dev/null
+++ b/crates/ide/src/view_hir.rs
@@ -0,0 +1,25 @@
1use hir::{Function, Semantics};
2use ide_db::base_db::FilePosition;
3use ide_db::RootDatabase;
4use syntax::{algo::find_node_at_offset, ast, AstNode};
5
6// Feature: View Hir
7//
8// |===
9// | Editor | Action Name
10//
11// | VS Code | **Rust Analyzer: View Hir**
12// |===
13pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String {
14 body_hir(db, position).unwrap_or("Not inside a function body".to_string())
15}
16
17fn body_hir(db: &RootDatabase, position: FilePosition) -> Option<String> {
18 let sema = Semantics::new(db);
19 let source_file = sema.parse(position.file_id);
20
21 let function = find_node_at_offset::<ast::Fn>(source_file.syntax(), position.offset)?;
22
23 let function: Function = sema.to_def(&function)?;
24 Some(function.debug_hir(db))
25}
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index ff10f71c3..436c59d2c 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -121,31 +121,56 @@ impl Definition {
121 121
122 if let Definition::Local(var) = self { 122 if let Definition::Local(var) = self {
123 let range = match var.parent(db) { 123 let range = match var.parent(db) {
124 DefWithBody::Function(f) => f.source(db).value.syntax().text_range(), 124 DefWithBody::Function(f) => {
125 DefWithBody::Const(c) => c.source(db).value.syntax().text_range(), 125 f.source(db).and_then(|src| Some(src.value.syntax().text_range()))
126 DefWithBody::Static(s) => s.source(db).value.syntax().text_range(), 126 }
127 DefWithBody::Const(c) => {
128 c.source(db).and_then(|src| Some(src.value.syntax().text_range()))
129 }
130 DefWithBody::Static(s) => {
131 s.source(db).and_then(|src| Some(src.value.syntax().text_range()))
132 }
127 }; 133 };
128 let mut res = FxHashMap::default(); 134 let mut res = FxHashMap::default();
129 res.insert(file_id, Some(range)); 135 res.insert(file_id, range);
130 return SearchScope::new(res); 136 return SearchScope::new(res);
131 } 137 }
132 138
133 if let Definition::LifetimeParam(param) = self { 139 if let Definition::LifetimeParam(param) = self {
140 #[allow(deprecated)]
134 let range = match param.parent(db) { 141 let range = match param.parent(db) {
135 hir::GenericDef::Function(it) => it.source(db).value.syntax().text_range(), 142 hir::GenericDef::Function(it) => {
143 it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
144 }
136 hir::GenericDef::Adt(it) => match it { 145 hir::GenericDef::Adt(it) => match it {
137 hir::Adt::Struct(it) => it.source(db).value.syntax().text_range(), 146 hir::Adt::Struct(it) => {
138 hir::Adt::Union(it) => it.source(db).value.syntax().text_range(), 147 it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
139 hir::Adt::Enum(it) => it.source(db).value.syntax().text_range(), 148 }
149 hir::Adt::Union(it) => {
150 it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
151 }
152 hir::Adt::Enum(it) => {
153 it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
154 }
140 }, 155 },
141 hir::GenericDef::Trait(it) => it.source(db).value.syntax().text_range(), 156 hir::GenericDef::Trait(it) => {
142 hir::GenericDef::TypeAlias(it) => it.source(db).value.syntax().text_range(), 157 it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
143 hir::GenericDef::Impl(it) => it.source(db).value.syntax().text_range(), 158 }
144 hir::GenericDef::Variant(it) => it.source(db).value.syntax().text_range(), 159 hir::GenericDef::TypeAlias(it) => {
145 hir::GenericDef::Const(it) => it.source(db).value.syntax().text_range(), 160 it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
161 }
162 hir::GenericDef::Impl(it) => {
163 it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
164 }
165 hir::GenericDef::Variant(it) => {
166 it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
167 }
168 hir::GenericDef::Const(it) => {
169 it.source(db).and_then(|src| Some(src.value.syntax().text_range()))
170 }
146 }; 171 };
147 let mut res = FxHashMap::default(); 172 let mut res = FxHashMap::default();
148 res.insert(file_id, Some(range)); 173 res.insert(file_id, range);
149 return SearchScope::new(res); 174 return SearchScope::new(res);
150 } 175 }
151 176
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index a23fb7a33..9445aec07 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -161,11 +161,12 @@ impl AnalysisStatsCmd {
161 } 161 }
162 let mut msg = format!("processing: {}", full_name); 162 let mut msg = format!("processing: {}", full_name);
163 if verbosity.is_verbose() { 163 if verbosity.is_verbose() {
164 let src = f.source(db); 164 if let Some(src) = f.source(db) {
165 let original_file = src.file_id.original_file(db); 165 let original_file = src.file_id.original_file(db);
166 let path = vfs.file_path(original_file); 166 let path = vfs.file_path(original_file);
167 let syntax_range = src.value.syntax().text_range(); 167 let syntax_range = src.value.syntax().text_range();
168 format_to!(msg, " ({} {:?})", path, syntax_range); 168 format_to!(msg, " ({} {:?})", path, syntax_range);
169 }
169 } 170 }
170 if verbosity.is_spammy() { 171 if verbosity.is_spammy() {
171 bar.println(msg.to_string()); 172 bar.println(msg.to_string());
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 948cfc17c..dd486070b 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -105,6 +105,16 @@ pub(crate) fn handle_syntax_tree(
105 Ok(res) 105 Ok(res)
106} 106}
107 107
108pub(crate) fn handle_view_hir(
109 snap: GlobalStateSnapshot,
110 params: lsp_types::TextDocumentPositionParams,
111) -> Result<String> {
112 let _p = profile::span("handle_view_hir");
113 let position = from_proto::file_position(&snap, params)?;
114 let res = snap.analysis.view_hir(position)?;
115 Ok(res)
116}
117
108pub(crate) fn handle_expand_macro( 118pub(crate) fn handle_expand_macro(
109 snap: GlobalStateSnapshot, 119 snap: GlobalStateSnapshot,
110 params: lsp_ext::ExpandMacroParams, 120 params: lsp_ext::ExpandMacroParams,
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 93ac45415..a85978737 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -53,6 +53,14 @@ pub struct SyntaxTreeParams {
53 pub range: Option<Range>, 53 pub range: Option<Range>,
54} 54}
55 55
56pub enum ViewHir {}
57
58impl Request for ViewHir {
59 type Params = lsp_types::TextDocumentPositionParams;
60 type Result = String;
61 const METHOD: &'static str = "rust-analyzer/viewHir";
62}
63
56pub enum ExpandMacro {} 64pub enum ExpandMacro {}
57 65
58impl Request for ExpandMacro { 66impl Request for ExpandMacro {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 5d55dc96e..8eca79f7e 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -443,6 +443,7 @@ impl GlobalState {
443 .on_sync::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))? 443 .on_sync::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))?
444 .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status) 444 .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
445 .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree) 445 .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
446 .on::<lsp_ext::ViewHir>(handlers::handle_view_hir)
446 .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro) 447 .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
447 .on::<lsp_ext::ParentModule>(handlers::handle_parent_module) 448 .on::<lsp_ext::ParentModule>(handlers::handle_parent_module)
448 .on::<lsp_ext::Runnables>(handlers::handle_runnables) 449 .on::<lsp_ext::Runnables>(handlers::handle_runnables)
diff --git a/docs/dev/README.md b/docs/dev/README.md
index 4a2f9feb3..55527bab0 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -227,6 +227,8 @@ There are also two VS Code commands which might be of interest:
227 227
228* `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection. 228* `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection.
229 229
230* `Rust Analyzer: View Hir` shows the HIR expressions within the function containing the cursor.
231
230 You can hover over syntax nodes in the opened text file to see the appropriate 232 You can hover over syntax nodes in the opened text file to see the appropriate
231 rust code that it refers to and the rust editor will also highlight the proper 233 rust code that it refers to and the rust editor will also highlight the proper
232 text range. 234 text range.
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 8c01db07c..78d86f060 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
1<!--- 1<!---
2lsp_ext.rs hash: 203fdf79b21b5987 2lsp_ext.rs hash: 91f2c62457e0a20f
3 3
4If you need to change the above hash to make the test pass, please check if you 4If you need to change the above hash to make the test pass, please check if you
5need to adjust this doc as well and ping this issue: 5need to adjust this doc as well and ping this issue:
@@ -449,6 +449,17 @@ interface SyntaxTeeParams {
449Returns textual representation of a parse tree for the file/selected region. 449Returns textual representation of a parse tree for the file/selected region.
450Primarily for debugging, but very useful for all people working on rust-analyzer itself. 450Primarily for debugging, but very useful for all people working on rust-analyzer itself.
451 451
452## View Hir
453
454**Method:** `rust-analyzer/viewHir`
455
456**Request:** `TextDocumentPositionParams`
457
458**Response:** `string`
459
460Returns a textual representation of the HIR of the function containing the cursor.
461For debugging or when working on rust-analyzer itself.
462
452## Expand Macro 463## Expand Macro
453 464
454**Method:** `rust-analyzer/expandMacro` 465**Method:** `rust-analyzer/expandMacro`
diff --git a/editors/code/package.json b/editors/code/package.json
index 587f11b90..3e55a3523 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -104,6 +104,11 @@
104 "category": "Rust Analyzer" 104 "category": "Rust Analyzer"
105 }, 105 },
106 { 106 {
107 "command": "rust-analyzer.viewHir",
108 "title": "View Hir",
109 "category": "Rust Analyzer"
110 },
111 {
107 "command": "rust-analyzer.expandMacro", 112 "command": "rust-analyzer.expandMacro",
108 "title": "Expand macro recursively", 113 "title": "Expand macro recursively",
109 "category": "Rust Analyzer" 114 "category": "Rust Analyzer"
@@ -1007,6 +1012,10 @@
1007 "when": "inRustProject" 1012 "when": "inRustProject"
1008 }, 1013 },
1009 { 1014 {
1015 "command": "rust-analyzer.viewHir",
1016 "when": "inRustProject"
1017 },
1018 {
1010 "command": "rust-analyzer.expandMacro", 1019 "command": "rust-analyzer.expandMacro",
1011 "when": "inRustProject" 1020 "when": "inRustProject"
1012 }, 1021 },
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index b12e134ca..c1c9f9754 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -340,6 +340,61 @@ export function syntaxTree(ctx: Ctx): Cmd {
340 }; 340 };
341} 341}
342 342
343// Opens the virtual file that will show the HIR of the function containing the cursor position
344//
345// The contents of the file come from the `TextDocumentContentProvider`
346export function viewHir(ctx: Ctx): Cmd {
347 const tdcp = new class implements vscode.TextDocumentContentProvider {
348 readonly uri = vscode.Uri.parse('rust-analyzer://viewHir/hir.txt');
349 readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
350 constructor() {
351 vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions);
352 vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions);
353 }
354
355 private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
356 if (isRustDocument(event.document)) {
357 // We need to order this after language server updates, but there's no API for that.
358 // Hence, good old sleep().
359 void sleep(10).then(() => this.eventEmitter.fire(this.uri));
360 }
361 }
362 private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
363 if (editor && isRustEditor(editor)) {
364 this.eventEmitter.fire(this.uri);
365 }
366 }
367
368 provideTextDocumentContent(_uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult<string> {
369 const rustEditor = ctx.activeRustEditor;
370 const client = ctx.client;
371 if (!rustEditor || !client) return '';
372
373 const params = {
374 textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(rustEditor.document),
375 position: client.code2ProtocolConverter.asPosition(
376 rustEditor.selection.active,
377 ),
378 };
379 return client.sendRequest(ra.viewHir, params, ct);
380 }
381
382 get onDidChange(): vscode.Event<vscode.Uri> {
383 return this.eventEmitter.event;
384 }
385 };
386
387 ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp));
388
389 return async () => {
390 const document = await vscode.workspace.openTextDocument(tdcp.uri);
391 tdcp.eventEmitter.fire(tdcp.uri);
392 void await vscode.window.showTextDocument(document, {
393 viewColumn: vscode.ViewColumn.Two,
394 preserveFocus: true
395 });
396 };
397}
343 398
344// Opens the virtual file that will show the syntax tree 399// Opens the virtual file that will show the syntax tree
345// 400//
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index 5e877ce65..d21a3db86 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -24,6 +24,7 @@ export interface SyntaxTreeParams {
24} 24}
25export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>("rust-analyzer/syntaxTree"); 25export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>("rust-analyzer/syntaxTree");
26 26
27export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>("rust-analyzer/viewHir");
27 28
28export interface ExpandMacroParams { 29export interface ExpandMacroParams {
29 textDocument: lc.TextDocumentIdentifier; 30 textDocument: lc.TextDocumentIdentifier;
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 282240d84..60907dfd4 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -105,6 +105,7 @@ async function tryActivate(context: vscode.ExtensionContext) {
105 ctx.registerCommand('joinLines', commands.joinLines); 105 ctx.registerCommand('joinLines', commands.joinLines);
106 ctx.registerCommand('parentModule', commands.parentModule); 106 ctx.registerCommand('parentModule', commands.parentModule);
107 ctx.registerCommand('syntaxTree', commands.syntaxTree); 107 ctx.registerCommand('syntaxTree', commands.syntaxTree);
108 ctx.registerCommand('viewHir', commands.viewHir);
108 ctx.registerCommand('expandMacro', commands.expandMacro); 109 ctx.registerCommand('expandMacro', commands.expandMacro);
109 ctx.registerCommand('run', commands.run); 110 ctx.registerCommand('run', commands.run);
110 ctx.registerCommand('debug', commands.debug); 111 ctx.registerCommand('debug', commands.debug);