aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/from_source.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/from_source.rs')
-rw-r--r--crates/ra_hir/src/from_source.rs137
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};
4use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; 4use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind};
5use ra_syntax::{ 5use 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
10use crate::{ 10use crate::{
@@ -52,56 +52,54 @@ impl FromSource for Trait {
52impl FromSource for Function { 52impl 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
100impl FromSource for Const { 79impl 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}
107impl FromSource for Static { 105impl FromSource for Static {
@@ -114,8 +112,27 @@ impl FromSource for Static {
114impl FromSource for TypeAlias { 112impl 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
278enum Container {
279 Trait(Trait),
280 ImplBlock(ImplBlock),
281 Module(Module),
282}
283
284impl 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.
267fn same_source<N: AstNode>(s1: &Source<N>, s2: &Source<N>) -> bool { 316fn 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)