|
1 | 1 | //! FIXME: write short doc here |
| 2 | +use either::Either; |
2 | 3 |
|
3 | | -use hir_def::{nameres::ModuleSource, AstItemDef, LocationCtx, ModuleId}; |
| 4 | +use hir_def::{ |
| 5 | + child_from_source::ChildFromSource, nameres::ModuleSource, AstItemDef, EnumVariantId, ImplId, |
| 6 | + LocationCtx, ModuleId, TraitId, VariantId, |
| 7 | +}; |
4 | 8 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; |
5 | 9 | use ra_syntax::{ |
6 | 10 | ast::{self, AstNode, NameOwner}, |
7 | | - match_ast, AstPtr, SyntaxNode, |
| 11 | + match_ast, SyntaxNode, |
8 | 12 | }; |
9 | 13 |
|
10 | 14 | use crate::{ |
11 | 15 | db::{AstDatabase, DefDatabase, HirDatabase}, |
12 | | - AssocItem, Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, |
13 | | - InFile, Local, MacroDef, Module, ModuleDef, Static, Struct, StructField, Trait, TypeAlias, |
14 | | - Union, VariantDef, |
| 16 | + Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, ImplBlock, InFile, Local, |
| 17 | + MacroDef, Module, Static, Struct, StructField, Trait, TypeAlias, Union, |
15 | 18 | }; |
16 | 19 |
|
17 | 20 | pub trait FromSource: Sized { |
@@ -50,98 +53,36 @@ impl FromSource for Trait { |
50 | 53 | impl FromSource for Function { |
51 | 54 | type Ast = ast::FnDef; |
52 | 55 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { |
53 | | - let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
54 | | - Container::Trait(it) => it.items(db), |
55 | | - Container::ImplBlock(it) => it.items(db), |
56 | | - Container::Module(m) => { |
57 | | - return m |
58 | | - .declarations(db) |
59 | | - .into_iter() |
60 | | - .filter_map(|it| match it { |
61 | | - ModuleDef::Function(it) => Some(it), |
62 | | - _ => None, |
63 | | - }) |
64 | | - .find(|it| same_source(&it.source(db), &src)) |
65 | | - } |
66 | | - }; |
67 | | - items |
68 | | - .into_iter() |
69 | | - .filter_map(|it| match it { |
70 | | - AssocItem::Function(it) => Some(it), |
71 | | - _ => None, |
72 | | - }) |
73 | | - .find(|it| same_source(&it.source(db), &src)) |
| 56 | + Container::find(db, src.as_ref().map(|it| it.syntax()))? |
| 57 | + .child_from_source(db, src) |
| 58 | + .map(Function::from) |
74 | 59 | } |
75 | 60 | } |
76 | 61 |
|
77 | 62 | impl FromSource for Const { |
78 | 63 | type Ast = ast::ConstDef; |
79 | 64 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { |
80 | | - let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
81 | | - Container::Trait(it) => it.items(db), |
82 | | - Container::ImplBlock(it) => it.items(db), |
83 | | - Container::Module(m) => { |
84 | | - return m |
85 | | - .declarations(db) |
86 | | - .into_iter() |
87 | | - .filter_map(|it| match it { |
88 | | - ModuleDef::Const(it) => Some(it), |
89 | | - _ => None, |
90 | | - }) |
91 | | - .find(|it| same_source(&it.source(db), &src)) |
92 | | - } |
93 | | - }; |
94 | | - items |
95 | | - .into_iter() |
96 | | - .filter_map(|it| match it { |
97 | | - AssocItem::Const(it) => Some(it), |
98 | | - _ => None, |
99 | | - }) |
100 | | - .find(|it| same_source(&it.source(db), &src)) |
| 65 | + Container::find(db, src.as_ref().map(|it| it.syntax()))? |
| 66 | + .child_from_source(db, src) |
| 67 | + .map(Const::from) |
101 | 68 | } |
102 | 69 | } |
103 | 70 | impl FromSource for Static { |
104 | 71 | type Ast = ast::StaticDef; |
105 | 72 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { |
106 | | - let module = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
107 | | - Container::Module(it) => it, |
108 | | - Container::Trait(_) | Container::ImplBlock(_) => return None, |
109 | | - }; |
110 | | - module |
111 | | - .declarations(db) |
112 | | - .into_iter() |
113 | | - .filter_map(|it| match it { |
114 | | - ModuleDef::Static(it) => Some(it), |
115 | | - _ => None, |
116 | | - }) |
117 | | - .find(|it| same_source(&it.source(db), &src)) |
| 73 | + match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
| 74 | + Container::Module(it) => it.id.child_from_source(db, src).map(Static::from), |
| 75 | + Container::Trait(_) | Container::ImplBlock(_) => None, |
| 76 | + } |
118 | 77 | } |
119 | 78 | } |
120 | 79 |
|
121 | 80 | impl FromSource for TypeAlias { |
122 | 81 | type Ast = ast::TypeAliasDef; |
123 | 82 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { |
124 | | - let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
125 | | - Container::Trait(it) => it.items(db), |
126 | | - Container::ImplBlock(it) => it.items(db), |
127 | | - Container::Module(m) => { |
128 | | - return m |
129 | | - .declarations(db) |
130 | | - .into_iter() |
131 | | - .filter_map(|it| match it { |
132 | | - ModuleDef::TypeAlias(it) => Some(it), |
133 | | - _ => None, |
134 | | - }) |
135 | | - .find(|it| same_source(&it.source(db), &src)) |
136 | | - } |
137 | | - }; |
138 | | - items |
139 | | - .into_iter() |
140 | | - .filter_map(|it| match it { |
141 | | - AssocItem::TypeAlias(it) => Some(it), |
142 | | - _ => None, |
143 | | - }) |
144 | | - .find(|it| same_source(&it.source(db), &src)) |
| 83 | + Container::find(db, src.as_ref().map(|it| it.syntax()))? |
| 84 | + .child_from_source(db, src) |
| 85 | + .map(TypeAlias::from) |
145 | 86 | } |
146 | 87 | } |
147 | 88 |
|
@@ -174,34 +115,33 @@ impl FromSource for EnumVariant { |
174 | 115 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { |
175 | 116 | let parent_enum = src.value.parent_enum(); |
176 | 117 | let src_enum = InFile { file_id: src.file_id, value: parent_enum }; |
177 | | - let variants = Enum::from_source(db, src_enum)?.variants(db); |
178 | | - variants.into_iter().find(|v| same_source(&v.source(db), &src)) |
| 118 | + let parent_enum = Enum::from_source(db, src_enum)?; |
| 119 | + parent_enum.id.child_from_source(db, src).map(EnumVariant::from) |
179 | 120 | } |
180 | 121 | } |
181 | 122 |
|
182 | 123 | impl FromSource for StructField { |
183 | 124 | type Ast = FieldSource; |
184 | 125 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { |
185 | | - let variant_def: VariantDef = match src.value { |
| 126 | + let variant_id: VariantId = match src.value { |
186 | 127 | FieldSource::Named(ref field) => { |
187 | 128 | let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?; |
188 | 129 | let src = InFile { file_id: src.file_id, value }; |
189 | 130 | let def = Struct::from_source(db, src)?; |
190 | | - VariantDef::from(def) |
| 131 | + def.id.into() |
191 | 132 | } |
192 | 133 | FieldSource::Pos(ref field) => { |
193 | 134 | let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?; |
194 | 135 | let src = InFile { file_id: src.file_id, value }; |
195 | 136 | let def = EnumVariant::from_source(db, src)?; |
196 | | - VariantDef::from(def) |
| 137 | + EnumVariantId::from(def).into() |
197 | 138 | } |
198 | 139 | }; |
199 | | - variant_def |
200 | | - .variant_data(db) |
201 | | - .fields() |
202 | | - .iter() |
203 | | - .map(|(id, _)| StructField { parent: variant_def, id }) |
204 | | - .find(|f| f.source(db) == src) |
| 140 | + let src = src.map(|field_source| match field_source { |
| 141 | + FieldSource::Pos(it) => Either::Left(it), |
| 142 | + FieldSource::Named(it) => Either::Right(it), |
| 143 | + }); |
| 144 | + variant_id.child_from_source(db, src).map(StructField::from) |
205 | 145 | } |
206 | 146 | } |
207 | 147 |
|
@@ -315,12 +255,21 @@ impl Container { |
315 | 255 | } |
316 | 256 | } |
317 | 257 |
|
318 | | -/// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are |
319 | | -/// equal if they point to exactly the same object. |
320 | | -/// |
321 | | -/// In general, we do not guarantee that we have exactly one instance of a |
322 | | -/// syntax tree for each file. We probably should add such guarantee, but, for |
323 | | -/// the time being, we will use identity-less AstPtr comparison. |
324 | | -fn same_source<N: AstNode>(s1: &InFile<N>, s2: &InFile<N>) -> bool { |
325 | | - s1.as_ref().map(AstPtr::new) == s2.as_ref().map(AstPtr::new) |
| 258 | +impl<CHILD, SOURCE> ChildFromSource<CHILD, SOURCE> for Container |
| 259 | +where |
| 260 | + TraitId: ChildFromSource<CHILD, SOURCE>, |
| 261 | + ImplId: ChildFromSource<CHILD, SOURCE>, |
| 262 | + ModuleId: ChildFromSource<CHILD, SOURCE>, |
| 263 | +{ |
| 264 | + fn child_from_source( |
| 265 | + &self, |
| 266 | + db: &impl DefDatabase, |
| 267 | + child_source: InFile<SOURCE>, |
| 268 | + ) -> Option<CHILD> { |
| 269 | + match self { |
| 270 | + Container::Trait(it) => it.id.child_from_source(db, child_source), |
| 271 | + Container::ImplBlock(it) => it.id.child_from_source(db, child_source), |
| 272 | + Container::Module(it) => it.id.child_from_source(db, child_source), |
| 273 | + } |
| 274 | + } |
326 | 275 | } |
0 commit comments