diff options
Diffstat (limited to 'crates/ra_hir/src/from_source.rs')
-rw-r--r-- | crates/ra_hir/src/from_source.rs | 137 |
1 files changed, 93 insertions, 44 deletions
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 303d5f138..b86307c58 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs | |||
@@ -4,7 +4,7 @@ use hir_def::{ModuleId, StructId, StructOrUnionId, UnionId}; | |||
4 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; | 4 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; |
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | ast::{self, AstNode, NameOwner}, | 6 | ast::{self, AstNode, NameOwner}, |
7 | match_ast, AstPtr, | 7 | match_ast, AstPtr, SyntaxNode, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
@@ -52,56 +52,54 @@ impl FromSource for Trait { | |||
52 | impl FromSource for Function { | 52 | impl FromSource for Function { |
53 | type Ast = ast::FnDef; | 53 | type Ast = ast::FnDef; |
54 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 54 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { |
55 | // FIXME: this doesn't try to handle nested declarations | 55 | let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
56 | for container in src.value.syntax().ancestors() { | 56 | Container::Trait(it) => it.items(db), |
57 | let res = match_ast! { | 57 | Container::ImplBlock(it) => it.items(db), |
58 | match container { | 58 | Container::Module(m) => { |
59 | ast::TraitDef(it) => { | 59 | return m |
60 | let c = Trait::from_source(db, src.with_value(it))?; | 60 | .declarations(db) |
61 | c.items(db) | 61 | .into_iter() |
62 | .into_iter() | 62 | .filter_map(|it| match it { |
63 | .filter_map(|it| match it { | 63 | ModuleDef::Function(it) => Some(it), |
64 | AssocItem::Function(it) => Some(it), | 64 | _ => None, |
65 | _ => None | 65 | }) |
66 | }) | 66 | .find(|it| same_source(&it.source(db), &src)) |
67 | .find(|it| same_source(&it.source(db), &src))? | 67 | } |
68 | }, | 68 | }; |
69 | ast::ImplBlock(it) => { | 69 | items |
70 | let c = ImplBlock::from_source(db, src.with_value(it))?; | ||
71 | c.items(db) | ||
72 | .into_iter() | ||
73 | .filter_map(|it| match it { | ||
74 | AssocItem::Function(it) => Some(it), | ||
75 | _ => None | ||
76 | }) | ||
77 | .find(|it| same_source(&it.source(db), &src))? | ||
78 | |||
79 | }, | ||
80 | _ => { continue }, | ||
81 | } | ||
82 | }; | ||
83 | return Some(res); | ||
84 | } | ||
85 | |||
86 | let module_source = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); | ||
87 | let c = Module::from_definition(db, src.with_value(module_source))?; | ||
88 | let res = c | ||
89 | .declarations(db) | ||
90 | .into_iter() | 70 | .into_iter() |
91 | .filter_map(|it| match it { | 71 | .filter_map(|it| match it { |
92 | ModuleDef::Function(it) => Some(it), | 72 | AssocItem::Function(it) => Some(it), |
93 | _ => None, | 73 | _ => None, |
94 | }) | 74 | }) |
95 | .find(|it| same_source(&it.source(db), &src)); | 75 | .find(|it| same_source(&it.source(db), &src)) |
96 | res | ||
97 | } | 76 | } |
98 | } | 77 | } |
99 | 78 | ||
100 | impl FromSource for Const { | 79 | impl FromSource for Const { |
101 | type Ast = ast::ConstDef; | 80 | type Ast = ast::ConstDef; |
102 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 81 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { |
103 | let id = from_source(db, src)?; | 82 | let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
104 | Some(Const { id }) | 83 | Container::Trait(it) => it.items(db), |
84 | Container::ImplBlock(it) => it.items(db), | ||
85 | Container::Module(m) => { | ||
86 | return m | ||
87 | .declarations(db) | ||
88 | .into_iter() | ||
89 | .filter_map(|it| match it { | ||
90 | ModuleDef::Const(it) => Some(it), | ||
91 | _ => None, | ||
92 | }) | ||
93 | .find(|it| same_source(&it.source(db), &src)) | ||
94 | } | ||
95 | }; | ||
96 | items | ||
97 | .into_iter() | ||
98 | .filter_map(|it| match it { | ||
99 | AssocItem::Const(it) => Some(it), | ||
100 | _ => None, | ||
101 | }) | ||
102 | .find(|it| same_source(&it.source(db), &src)) | ||
105 | } | 103 | } |
106 | } | 104 | } |
107 | impl FromSource for Static { | 105 | impl FromSource for Static { |
@@ -114,8 +112,27 @@ impl FromSource for Static { | |||
114 | impl FromSource for TypeAlias { | 112 | impl FromSource for TypeAlias { |
115 | type Ast = ast::TypeAliasDef; | 113 | type Ast = ast::TypeAliasDef; |
116 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 114 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { |
117 | let id = from_source(db, src)?; | 115 | let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
118 | Some(TypeAlias { id }) | 116 | Container::Trait(it) => it.items(db), |
117 | Container::ImplBlock(it) => it.items(db), | ||
118 | Container::Module(m) => { | ||
119 | return m | ||
120 | .declarations(db) | ||
121 | .into_iter() | ||
122 | .filter_map(|it| match it { | ||
123 | ModuleDef::TypeAlias(it) => Some(it), | ||
124 | _ => None, | ||
125 | }) | ||
126 | .find(|it| same_source(&it.source(db), &src)) | ||
127 | } | ||
128 | }; | ||
129 | items | ||
130 | .into_iter() | ||
131 | .filter_map(|it| match it { | ||
132 | AssocItem::TypeAlias(it) => Some(it), | ||
133 | _ => None, | ||
134 | }) | ||
135 | .find(|it| same_source(&it.source(db), &src)) | ||
119 | } | 136 | } |
120 | } | 137 | } |
121 | 138 | ||
@@ -258,11 +275,43 @@ where | |||
258 | Some(DEF::from_ast(ctx, &src.value)) | 275 | Some(DEF::from_ast(ctx, &src.value)) |
259 | } | 276 | } |
260 | 277 | ||
278 | enum Container { | ||
279 | Trait(Trait), | ||
280 | ImplBlock(ImplBlock), | ||
281 | Module(Module), | ||
282 | } | ||
283 | |||
284 | impl Container { | ||
285 | fn find(db: &impl DefDatabase, src: Source<&SyntaxNode>) -> Option<Container> { | ||
286 | // FIXME: this doesn't try to handle nested declarations | ||
287 | for container in src.value.ancestors() { | ||
288 | let res = match_ast! { | ||
289 | match container { | ||
290 | ast::TraitDef(it) => { | ||
291 | let c = Trait::from_source(db, src.with_value(it))?; | ||
292 | Container::Trait(c) | ||
293 | }, | ||
294 | ast::ImplBlock(it) => { | ||
295 | let c = ImplBlock::from_source(db, src.with_value(it))?; | ||
296 | Container::ImplBlock(c) | ||
297 | }, | ||
298 | _ => { continue }, | ||
299 | } | ||
300 | }; | ||
301 | return Some(res); | ||
302 | } | ||
303 | |||
304 | let module_source = ModuleSource::from_child_node(db, src); | ||
305 | let c = Module::from_definition(db, src.with_value(module_source))?; | ||
306 | Some(Container::Module(c)) | ||
307 | } | ||
308 | } | ||
309 | |||
261 | /// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are | 310 | /// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are |
262 | /// equal if they point to exactly the same object. | 311 | /// equal if they point to exactly the same object. |
263 | /// | 312 | /// |
264 | /// In general, we do not guarantee that we have exactly one instance of a | 313 | /// In general, we do not guarantee that we have exactly one instance of a |
265 | /// syntax tree for each file. We probably should add such guanratree, but, for | 314 | /// syntax tree for each file. We probably should add such guarantee, but, for |
266 | /// the time being, we will use identity-less AstPtr comparison. | 315 | /// the time being, we will use identity-less AstPtr comparison. |
267 | fn same_source<N: AstNode>(s1: &Source<N>, s2: &Source<N>) -> bool { | 316 | fn same_source<N: AstNode>(s1: &Source<N>, s2: &Source<N>) -> bool { |
268 | s1.as_ref().map(AstPtr::new) == s2.as_ref().map(AstPtr::new) | 317 | s1.as_ref().map(AstPtr::new) == s2.as_ref().map(AstPtr::new) |