diff options
Diffstat (limited to 'crates/ra_ide_api/src/name_kind.rs')
-rw-r--r-- | crates/ra_ide_api/src/name_kind.rs | 432 |
1 files changed, 266 insertions, 166 deletions
diff --git a/crates/ra_ide_api/src/name_kind.rs b/crates/ra_ide_api/src/name_kind.rs index 5dc6b1a13..31f6f277d 100644 --- a/crates/ra_ide_api/src/name_kind.rs +++ b/crates/ra_ide_api/src/name_kind.rs | |||
@@ -1,101 +1,127 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{Either, FromSource, HasSource}; | 3 | use hir::{ |
4 | db::AstDatabase, Adt, AssocItem, DefWithBody, Either, EnumVariant, FromSource, HasSource, | ||
5 | HirFileId, MacroDef, ModuleDef, ModuleSource, Path, PathResolution, SourceAnalyzer, | ||
6 | StructField, Ty, VariantDef, | ||
7 | }; | ||
4 | use ra_db::FileId; | 8 | use ra_db::FileId; |
5 | use ra_syntax::{ast, ast::VisibilityOwner, AstNode, AstPtr}; | 9 | use ra_syntax::{ast, ast::VisibilityOwner, AstNode, AstPtr}; |
6 | use test_utils::tested_by; | ||
7 | 10 | ||
8 | use crate::db::RootDatabase; | 11 | use crate::db::RootDatabase; |
9 | 12 | ||
13 | pub enum NameKind { | ||
14 | Macro(MacroDef), | ||
15 | FieldAccess(StructField), | ||
16 | AssocItem(AssocItem), | ||
17 | Def(ModuleDef), | ||
18 | SelfType(Ty), | ||
19 | Pat((DefWithBody, AstPtr<ast::BindPat>)), | ||
20 | SelfParam(AstPtr<ast::SelfParam>), | ||
21 | GenericParam(u32), | ||
22 | } | ||
23 | |||
10 | pub(crate) struct Declaration { | 24 | pub(crate) struct Declaration { |
11 | visibility: Option<ast::Visibility>, | 25 | visibility: Option<ast::Visibility>, |
12 | container: hir::ModuleSource, | 26 | container: ModuleSource, |
13 | pub item: NameKind, | 27 | pub item: NameKind, |
14 | } | 28 | } |
15 | 29 | ||
16 | pub(crate) enum NameKind { | 30 | trait HasDeclaration { |
17 | Macro(hir::MacroDef), | 31 | type Def; |
18 | FieldAccess(hir::StructField), | 32 | type Ref; |
19 | AssocItem(hir::AssocItem), | 33 | |
20 | Def(hir::ModuleDef), | 34 | fn declaration(self, db: &RootDatabase) -> Declaration; |
21 | SelfType(hir::Ty), | 35 | fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option<Declaration>; |
22 | Pat(AstPtr<ast::BindPat>), | 36 | fn from_ref( |
23 | SelfParam(AstPtr<ast::SelfParam>), | 37 | db: &RootDatabase, |
24 | GenericParam(u32), | 38 | analyzer: &SourceAnalyzer, |
39 | refer: Self::Ref, | ||
40 | ) -> Option<Declaration>; | ||
41 | } | ||
42 | |||
43 | macro_rules! match_ast { | ||
44 | (match $node:ident { | ||
45 | $( ast::$ast:ident($it:ident) => $res:block, )* | ||
46 | _ => $catch_all:expr, | ||
47 | }) => {{ | ||
48 | $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* | ||
49 | { $catch_all } | ||
50 | }}; | ||
25 | } | 51 | } |
26 | 52 | ||
27 | pub(crate) fn classify_name_ref( | 53 | pub(crate) fn classify_name_ref( |
28 | db: &RootDatabase, | 54 | db: &RootDatabase, |
29 | analyzer: &hir::SourceAnalyzer, | 55 | file_id: FileId, |
56 | analyzer: &SourceAnalyzer, | ||
30 | name_ref: &ast::NameRef, | 57 | name_ref: &ast::NameRef, |
31 | ) -> Option<NameKind> { | 58 | ) -> Option<Declaration> { |
32 | use NameKind::*; | 59 | let parent = name_ref.syntax().parent()?; |
33 | 60 | match_ast! { | |
34 | // Check if it is a method | 61 | match parent { |
35 | if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) { | 62 | ast::MethodCallExpr(it) => { |
36 | tested_by!(goto_definition_works_for_methods); | 63 | return AssocItem::from_ref(db, analyzer, it); |
37 | if let Some(func) = analyzer.resolve_method_call(&method_call) { | 64 | }, |
38 | return Some(AssocItem(func.into())); | 65 | ast::FieldExpr(it) => { |
66 | if let Some(field) = analyzer.resolve_field(&it) { | ||
67 | return Some(field.declaration(db)); | ||
68 | } | ||
69 | }, | ||
70 | ast::RecordField(it) => { | ||
71 | if let Some(record_lit) = it.syntax().ancestors().find_map(ast::RecordLit::cast) { | ||
72 | let variant_def = analyzer.resolve_record_literal(&record_lit)?; | ||
73 | let hir_path = Path::from_name_ref(name_ref); | ||
74 | let hir_name = hir_path.as_ident()?; | ||
75 | let field = variant_def.field(db, hir_name)?; | ||
76 | return Some(field.declaration(db)); | ||
77 | } | ||
78 | }, | ||
79 | _ => (), | ||
39 | } | 80 | } |
40 | } | 81 | } |
41 | 82 | ||
42 | // It could be a macro call | 83 | let file_id = file_id.into(); |
43 | if let Some(macro_call) = name_ref | 84 | let container = parent.ancestors().find_map(|node| { |
44 | .syntax() | 85 | if let Some(it) = ast::Module::cast(node.clone()) { |
45 | .parent() | 86 | Some(ModuleSource::Module(it)) |
46 | .and_then(|node| node.parent()) | 87 | } else if let Some(it) = ast::SourceFile::cast(node.clone()) { |
47 | .and_then(|node| node.parent()) | 88 | Some(ModuleSource::SourceFile(it)) |
48 | .and_then(ast::MacroCall::cast) | 89 | } else { |
49 | { | 90 | None |
50 | tested_by!(goto_definition_works_for_macros); | ||
51 | if let Some(mac) = analyzer.resolve_macro_call(db, ¯o_call) { | ||
52 | return Some(Macro(mac)); | ||
53 | } | 91 | } |
54 | } | 92 | })?; |
55 | |||
56 | // It could also be a field access | ||
57 | if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast) { | ||
58 | tested_by!(goto_definition_works_for_fields); | ||
59 | if let Some(field) = analyzer.resolve_field(&field_expr) { | ||
60 | return Some(FieldAccess(field)); | ||
61 | }; | ||
62 | } | ||
63 | |||
64 | // It could also be a named field | ||
65 | if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::RecordField::cast) { | ||
66 | tested_by!(goto_definition_works_for_record_fields); | ||
67 | 93 | ||
68 | if let Some(record_lit) = field_expr.syntax().ancestors().find_map(ast::RecordLit::cast) { | 94 | if let Some(macro_call) = |
69 | let variant_def = analyzer.resolve_record_literal(&record_lit)?; | 95 | parent.parent().and_then(|node| node.parent()).and_then(ast::MacroCall::cast) |
70 | let hir_path = hir::Path::from_name_ref(name_ref); | 96 | { |
71 | let hir_name = hir_path.as_ident()?; | 97 | if let Some(mac) = analyzer.resolve_macro_call(db, ¯o_call) { |
72 | let field = variant_def.field(db, hir_name)?; | 98 | return Some(Declaration { item: NameKind::Macro(mac), container, visibility: None }); |
73 | return Some(FieldAccess(field)); | ||
74 | } | 99 | } |
75 | } | 100 | } |
76 | 101 | ||
77 | // General case, a path or a local: | 102 | // General case, a path or a local: |
78 | if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { | 103 | let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; |
79 | if let Some(resolved) = analyzer.resolve_path(db, &path) { | 104 | let resolved = analyzer.resolve_path(db, &path)?; |
80 | return match resolved { | 105 | match resolved { |
81 | hir::PathResolution::Def(def) => Some(Def(def)), | 106 | PathResolution::Def(def) => Some(def.declaration(db)), |
82 | hir::PathResolution::LocalBinding(Either::A(pat)) => Some(Pat(pat)), | 107 | PathResolution::LocalBinding(Either::A(pat)) => decl_from_pat(db, file_id, pat), |
83 | hir::PathResolution::LocalBinding(Either::B(par)) => Some(SelfParam(par)), | 108 | PathResolution::LocalBinding(Either::B(par)) => { |
84 | hir::PathResolution::GenericParam(par) => { | 109 | Some(Declaration { item: NameKind::SelfParam(par), container, visibility: None }) |
85 | // FIXME: get generic param def | 110 | } |
86 | Some(GenericParam(par)) | 111 | PathResolution::GenericParam(par) => { |
87 | } | 112 | // FIXME: get generic param def |
88 | hir::PathResolution::Macro(def) => Some(Macro(def)), | 113 | Some(Declaration { item: NameKind::GenericParam(par), container, visibility: None }) |
89 | hir::PathResolution::SelfType(impl_block) => { | 114 | } |
90 | let ty = impl_block.target_ty(db); | 115 | PathResolution::Macro(def) => { |
91 | Some(SelfType(ty)) | 116 | Some(Declaration { item: NameKind::Macro(def), container, visibility: None }) |
92 | } | ||
93 | hir::PathResolution::AssocItem(assoc) => Some(AssocItem(assoc)), | ||
94 | }; | ||
95 | } | 117 | } |
118 | PathResolution::SelfType(impl_block) => { | ||
119 | let ty = impl_block.target_ty(db); | ||
120 | let container = impl_block.module().definition_source(db).ast; | ||
121 | Some(Declaration { item: NameKind::SelfType(ty), container, visibility: None }) | ||
122 | } | ||
123 | PathResolution::AssocItem(assoc) => Some(assoc.declaration(db)), | ||
96 | } | 124 | } |
97 | |||
98 | None | ||
99 | } | 125 | } |
100 | 126 | ||
101 | pub(crate) fn classify_name( | 127 | pub(crate) fn classify_name( |
@@ -103,114 +129,188 @@ pub(crate) fn classify_name( | |||
103 | file_id: FileId, | 129 | file_id: FileId, |
104 | name: &ast::Name, | 130 | name: &ast::Name, |
105 | ) -> Option<Declaration> { | 131 | ) -> Option<Declaration> { |
106 | use NameKind::*; | ||
107 | |||
108 | let parent = name.syntax().parent()?; | 132 | let parent = name.syntax().parent()?; |
109 | let file_id = file_id.into(); | 133 | let file_id = file_id.into(); |
110 | 134 | ||
111 | macro_rules! match_ast { | 135 | match_ast! { |
112 | (match $node:ident { | ||
113 | $( ast::$ast:ident($it:ident) => $res:block, )* | ||
114 | _ => $catch_all:block, | ||
115 | }) => {{ | ||
116 | $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* | ||
117 | $catch_all | ||
118 | }}; | ||
119 | } | ||
120 | |||
121 | let container = parent.ancestors().find_map(|n| { | ||
122 | match_ast! { | ||
123 | match n { | ||
124 | ast::Module(it) => { Some(hir::ModuleSource::Module(it)) }, | ||
125 | ast::SourceFile(it) => { Some(hir::ModuleSource::SourceFile(it)) }, | ||
126 | _ => { None }, | ||
127 | } | ||
128 | } | ||
129 | })?; | ||
130 | |||
131 | // FIXME: add ast::MacroCall(it) | ||
132 | let (item, visibility) = match_ast! { | ||
133 | match parent { | 136 | match parent { |
134 | ast::BindPat(it) => { | 137 | ast::BindPat(it) => { |
135 | let pat = AstPtr::new(&it); | 138 | decl_from_pat(db, file_id, AstPtr::new(&it)) |
136 | (Pat(pat), None) | ||
137 | }, | 139 | }, |
138 | ast::RecordFieldDef(it) => { | 140 | ast::RecordFieldDef(it) => { |
139 | let src = hir::Source { file_id, ast: hir::FieldSource::Named(it) }; | 141 | StructField::from_def(db, file_id, it) |
140 | let field = hir::StructField::from_source(db, src)?; | ||
141 | let visibility = match field.parent_def(db) { | ||
142 | hir::VariantDef::Struct(s) => s.source(db).ast.visibility(), | ||
143 | hir::VariantDef::EnumVariant(e) => e.source(db).ast.parent_enum().visibility(), | ||
144 | }; | ||
145 | (FieldAccess(field), visibility) | ||
146 | }, | ||
147 | ast::FnDef(it) => { | ||
148 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
149 | let src = hir::Source { file_id, ast: ast::ImplItem::from(it.clone()) }; | ||
150 | let item = hir::AssocItem::from_source(db, src)?; | ||
151 | (AssocItem(item), it.visibility()) | ||
152 | } else { | ||
153 | let src = hir::Source { file_id, ast: it.clone() }; | ||
154 | let def = hir::Function::from_source(db, src)?; | ||
155 | (Def(def.into()), it.visibility()) | ||
156 | } | ||
157 | }, | ||
158 | ast::ConstDef(it) => { | ||
159 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
160 | let src = hir::Source { file_id, ast: ast::ImplItem::from(it.clone()) }; | ||
161 | let item = hir::AssocItem::from_source(db, src)?; | ||
162 | (AssocItem(item), it.visibility()) | ||
163 | } else { | ||
164 | let src = hir::Source { file_id, ast: it.clone() }; | ||
165 | let def = hir::Const::from_source(db, src)?; | ||
166 | (Def(def.into()), it.visibility()) | ||
167 | } | ||
168 | }, | ||
169 | ast::TypeAliasDef(it) => { | ||
170 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
171 | let src = hir::Source { file_id, ast: ast::ImplItem::from(it.clone()) }; | ||
172 | let item = hir::AssocItem::from_source(db, src)?; | ||
173 | (AssocItem(item), it.visibility()) | ||
174 | } else { | ||
175 | let src = hir::Source { file_id, ast: it.clone() }; | ||
176 | let def = hir::TypeAlias::from_source(db, src)?; | ||
177 | (Def(def.into()), it.visibility()) | ||
178 | } | ||
179 | }, | ||
180 | ast::Module(it) => { | ||
181 | let src = hir::Source { file_id, ast: hir::ModuleSource::Module(it.clone()) }; | ||
182 | let def = hir::Module::from_definition(db, src)?; | ||
183 | (Def(def.into()), it.visibility()) | ||
184 | }, | ||
185 | ast::StructDef(it) => { | ||
186 | let src = hir::Source { file_id, ast: it.clone() }; | ||
187 | let def = hir::Struct::from_source(db, src)?; | ||
188 | (Def(def.into()), it.visibility()) | ||
189 | }, | 142 | }, |
190 | ast::EnumDef(it) => { | 143 | ast::ImplItem(it) => { |
191 | let src = hir::Source { file_id, ast: it.clone() }; | 144 | AssocItem::from_def(db, file_id, it.clone()).or_else(|| { |
192 | let def = hir::Enum::from_source(db, src)?; | 145 | match it { |
193 | (Def(def.into()), it.visibility()) | 146 | ast::ImplItem::FnDef(f) => ModuleDef::from_def(db, file_id, f.into()), |
194 | }, | 147 | ast::ImplItem::ConstDef(c) => ModuleDef::from_def(db, file_id, c.into()), |
195 | ast::TraitDef(it) => { | 148 | ast::ImplItem::TypeAliasDef(a) => ModuleDef::from_def(db, file_id, a.into()), |
196 | let src = hir::Source { file_id, ast: it.clone() }; | 149 | } |
197 | let def = hir::Trait::from_source(db, src)?; | 150 | }) |
198 | (Def(def.into()), it.visibility()) | ||
199 | }, | ||
200 | ast::StaticDef(it) => { | ||
201 | let src = hir::Source { file_id, ast: it.clone() }; | ||
202 | let def = hir::Static::from_source(db, src)?; | ||
203 | (Def(def.into()), it.visibility()) | ||
204 | }, | 151 | }, |
205 | ast::EnumVariant(it) => { | 152 | ast::EnumVariant(it) => { |
206 | let src = hir::Source { file_id, ast: it.clone() }; | 153 | let src = hir::Source { file_id, ast: it.clone() }; |
207 | let def = hir::EnumVariant::from_source(db, src)?; | 154 | let def: ModuleDef = EnumVariant::from_source(db, src)?.into(); |
208 | (Def(def.into()), it.parent_enum().visibility()) | 155 | Some(def.declaration(db)) |
209 | }, | 156 | }, |
210 | _ => { | 157 | ast::ModuleItem(it) => { |
211 | return None; | 158 | ModuleDef::from_def(db, file_id, it) |
212 | }, | 159 | }, |
160 | _ => None, | ||
213 | } | 161 | } |
214 | }; | 162 | } |
215 | Some(Declaration { item, container, visibility }) | 163 | } |
164 | |||
165 | fn decl_from_pat( | ||
166 | db: &RootDatabase, | ||
167 | file_id: HirFileId, | ||
168 | pat: AstPtr<ast::BindPat>, | ||
169 | ) -> Option<Declaration> { | ||
170 | let root = db.parse_or_expand(file_id)?; | ||
171 | // FIXME: use match_ast! | ||
172 | let def = pat.to_node(&root).syntax().ancestors().find_map(|node| { | ||
173 | if let Some(it) = ast::FnDef::cast(node.clone()) { | ||
174 | let src = hir::Source { file_id, ast: it }; | ||
175 | Some(hir::Function::from_source(db, src)?.into()) | ||
176 | } else if let Some(it) = ast::ConstDef::cast(node.clone()) { | ||
177 | let src = hir::Source { file_id, ast: it }; | ||
178 | Some(hir::Const::from_source(db, src)?.into()) | ||
179 | } else if let Some(it) = ast::StaticDef::cast(node.clone()) { | ||
180 | let src = hir::Source { file_id, ast: it }; | ||
181 | Some(hir::Static::from_source(db, src)?.into()) | ||
182 | } else { | ||
183 | None | ||
184 | } | ||
185 | })?; | ||
186 | let item = NameKind::Pat((def, pat)); | ||
187 | let container = def.module(db).definition_source(db).ast; | ||
188 | Some(Declaration { item, container, visibility: None }) | ||
189 | } | ||
190 | |||
191 | impl HasDeclaration for StructField { | ||
192 | type Def = ast::RecordFieldDef; | ||
193 | type Ref = ast::FieldExpr; | ||
194 | |||
195 | fn declaration(self, db: &RootDatabase) -> Declaration { | ||
196 | let item = NameKind::FieldAccess(self); | ||
197 | let parent = self.parent_def(db); | ||
198 | let container = parent.module(db).definition_source(db).ast; | ||
199 | let visibility = match parent { | ||
200 | VariantDef::Struct(s) => s.source(db).ast.visibility(), | ||
201 | VariantDef::EnumVariant(e) => e.source(db).ast.parent_enum().visibility(), | ||
202 | }; | ||
203 | Declaration { item, container, visibility } | ||
204 | } | ||
205 | |||
206 | fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option<Declaration> { | ||
207 | let src = hir::Source { file_id, ast: hir::FieldSource::Named(def) }; | ||
208 | let field = StructField::from_source(db, src)?; | ||
209 | Some(field.declaration(db)) | ||
210 | } | ||
211 | |||
212 | fn from_ref( | ||
213 | db: &RootDatabase, | ||
214 | analyzer: &SourceAnalyzer, | ||
215 | refer: Self::Ref, | ||
216 | ) -> Option<Declaration> { | ||
217 | let field = analyzer.resolve_field(&refer)?; | ||
218 | Some(field.declaration(db)) | ||
219 | } | ||
220 | } | ||
221 | |||
222 | impl HasDeclaration for AssocItem { | ||
223 | type Def = ast::ImplItem; | ||
224 | type Ref = ast::MethodCallExpr; | ||
225 | |||
226 | fn declaration(self, db: &RootDatabase) -> Declaration { | ||
227 | let item = NameKind::AssocItem(self); | ||
228 | let container = self.module(db).definition_source(db).ast; | ||
229 | let visibility = match self { | ||
230 | AssocItem::Function(f) => f.source(db).ast.visibility(), | ||
231 | AssocItem::Const(c) => c.source(db).ast.visibility(), | ||
232 | AssocItem::TypeAlias(a) => a.source(db).ast.visibility(), | ||
233 | }; | ||
234 | Declaration { item, container, visibility } | ||
235 | } | ||
236 | |||
237 | fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option<Declaration> { | ||
238 | let src = hir::Source { file_id, ast: def }; | ||
239 | let item = AssocItem::from_source(db, src)?; | ||
240 | Some(item.declaration(db)) | ||
241 | } | ||
242 | |||
243 | fn from_ref( | ||
244 | db: &RootDatabase, | ||
245 | analyzer: &SourceAnalyzer, | ||
246 | refer: Self::Ref, | ||
247 | ) -> Option<Declaration> { | ||
248 | let func: AssocItem = analyzer.resolve_method_call(&refer)?.into(); | ||
249 | Some(func.declaration(db)) | ||
250 | } | ||
216 | } | 251 | } |
252 | |||
253 | impl HasDeclaration for ModuleDef { | ||
254 | type Def = ast::ModuleItem; | ||
255 | type Ref = ast::Path; | ||
256 | |||
257 | fn declaration(self, db: &RootDatabase) -> Declaration { | ||
258 | // FIXME: use macro | ||
259 | let (container, visibility) = match self { | ||
260 | ModuleDef::Module(it) => { | ||
261 | let container = | ||
262 | it.parent(db).or_else(|| Some(it)).unwrap().definition_source(db).ast; | ||
263 | let visibility = it.declaration_source(db).and_then(|s| s.ast.visibility()); | ||
264 | (container, visibility) | ||
265 | } | ||
266 | ModuleDef::EnumVariant(it) => { | ||
267 | let container = it.module(db).definition_source(db).ast; | ||
268 | let visibility = it.source(db).ast.parent_enum().visibility(); | ||
269 | (container, visibility) | ||
270 | } | ||
271 | ModuleDef::Function(it) => { | ||
272 | (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) | ||
273 | } | ||
274 | ModuleDef::Const(it) => { | ||
275 | (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) | ||
276 | } | ||
277 | ModuleDef::Static(it) => { | ||
278 | (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) | ||
279 | } | ||
280 | ModuleDef::Trait(it) => { | ||
281 | (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) | ||
282 | } | ||
283 | ModuleDef::TypeAlias(it) => { | ||
284 | (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) | ||
285 | } | ||
286 | ModuleDef::Adt(Adt::Struct(it)) => { | ||
287 | (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) | ||
288 | } | ||
289 | ModuleDef::Adt(Adt::Union(it)) => { | ||
290 | (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) | ||
291 | } | ||
292 | ModuleDef::Adt(Adt::Enum(it)) => { | ||
293 | (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) | ||
294 | } | ||
295 | ModuleDef::BuiltinType(..) => unreachable!(), | ||
296 | }; | ||
297 | let item = NameKind::Def(self); | ||
298 | Declaration { item, container, visibility } | ||
299 | } | ||
300 | |||
301 | fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option<Declaration> { | ||
302 | let src = hir::Source { file_id, ast: def }; | ||
303 | let def = ModuleDef::from_source(db, src)?; | ||
304 | Some(def.declaration(db)) | ||
305 | } | ||
306 | |||
307 | fn from_ref( | ||
308 | db: &RootDatabase, | ||
309 | analyzer: &SourceAnalyzer, | ||
310 | refer: Self::Ref, | ||
311 | ) -> Option<Declaration> { | ||
312 | None | ||
313 | } | ||
314 | } | ||
315 | |||
316 | // FIXME: impl HasDeclaration for hir::MacroDef | ||