|
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