diff options
author | Aleksey Kladov <[email protected]> | 2019-12-05 14:16:59 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-12-05 15:55:54 +0000 |
commit | 0c0ce1ae418a2f3f4fc125bd701cdb327f607002 (patch) | |
tree | 596e533284a136297c8443094434c9738d24c435 /crates/ra_hir | |
parent | 4c0bd068da39e74c66104206e27c270454e3562e (diff) |
Introduce ChildFromSource
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/from_source.rs | 141 |
1 files changed, 40 insertions, 101 deletions
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 18d87f6d7..58203c721 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs | |||
@@ -1,17 +1,20 @@ | |||
1 | //! FIXME: write short doc here | 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, | ||
6 | LocationCtx, ModuleId, VariantId, | ||
7 | }; | ||
4 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; | 8 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; |
5 | use ra_syntax::{ | 9 | use ra_syntax::{ |
6 | ast::{self, AstNode, NameOwner}, | 10 | ast::{self, AstNode, NameOwner}, |
7 | match_ast, AstPtr, SyntaxNode, | 11 | match_ast, SyntaxNode, |
8 | }; | 12 | }; |
9 | 13 | ||
10 | use crate::{ | 14 | use crate::{ |
11 | db::{AstDatabase, DefDatabase, HirDatabase}, | 15 | db::{AstDatabase, DefDatabase, HirDatabase}, |
12 | AssocItem, Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, | 16 | Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, ImplBlock, InFile, Local, |
13 | InFile, Local, MacroDef, Module, ModuleDef, Static, Struct, StructField, Trait, TypeAlias, | 17 | MacroDef, Module, Static, Struct, StructField, Trait, TypeAlias, Union, |
14 | Union, VariantDef, | ||
15 | }; | 18 | }; |
16 | 19 | ||
17 | pub trait FromSource: Sized { | 20 | pub trait FromSource: Sized { |
@@ -50,98 +53,45 @@ impl FromSource for Trait { | |||
50 | impl FromSource for Function { | 53 | impl FromSource for Function { |
51 | type Ast = ast::FnDef; | 54 | type Ast = ast::FnDef; |
52 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { | 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()))? { | 56 | match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
54 | Container::Trait(it) => it.items(db), | 57 | Container::Trait(it) => it.id.child_from_source(db, src), |
55 | Container::ImplBlock(it) => it.items(db), | 58 | Container::ImplBlock(it) => it.id.child_from_source(db, src), |
56 | Container::Module(m) => { | 59 | Container::Module(it) => it.id.child_from_source(db, src), |
57 | return m | 60 | } |
58 | .declarations(db) | 61 | .map(Function::from) |
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)) | ||
74 | } | 62 | } |
75 | } | 63 | } |
76 | 64 | ||
77 | impl FromSource for Const { | 65 | impl FromSource for Const { |
78 | type Ast = ast::ConstDef; | 66 | type Ast = ast::ConstDef; |
79 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { | 67 | 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()))? { | 68 | match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
81 | Container::Trait(it) => it.items(db), | 69 | Container::Trait(it) => it.id.child_from_source(db, src), |
82 | Container::ImplBlock(it) => it.items(db), | 70 | Container::ImplBlock(it) => it.id.child_from_source(db, src), |
83 | Container::Module(m) => { | 71 | Container::Module(it) => it.id.child_from_source(db, src), |
84 | return m | 72 | } |
85 | .declarations(db) | 73 | .map(Const::from) |
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)) | ||
101 | } | 74 | } |
102 | } | 75 | } |
103 | impl FromSource for Static { | 76 | impl FromSource for Static { |
104 | type Ast = ast::StaticDef; | 77 | type Ast = ast::StaticDef; |
105 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { | 78 | 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()))? { | 79 | match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
107 | Container::Module(it) => it, | 80 | Container::Module(it) => it.id.child_from_source(db, src).map(Static::from), |
108 | Container::Trait(_) | Container::ImplBlock(_) => return None, | 81 | Container::Trait(_) | Container::ImplBlock(_) => None, |
109 | }; | 82 | } |
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)) | ||
118 | } | 83 | } |
119 | } | 84 | } |
120 | 85 | ||
121 | impl FromSource for TypeAlias { | 86 | impl FromSource for TypeAlias { |
122 | type Ast = ast::TypeAliasDef; | 87 | type Ast = ast::TypeAliasDef; |
123 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { | 88 | 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()))? { | 89 | match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
125 | Container::Trait(it) => it.items(db), | 90 | Container::Trait(it) => it.id.child_from_source(db, src), |
126 | Container::ImplBlock(it) => it.items(db), | 91 | Container::ImplBlock(it) => it.id.child_from_source(db, src), |
127 | Container::Module(m) => { | 92 | Container::Module(it) => it.id.child_from_source(db, src), |
128 | return m | 93 | } |
129 | .declarations(db) | 94 | .map(TypeAlias::from) |
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)) | ||
145 | } | 95 | } |
146 | } | 96 | } |
147 | 97 | ||
@@ -174,34 +124,33 @@ impl FromSource for EnumVariant { | |||
174 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { | 124 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { |
175 | let parent_enum = src.value.parent_enum(); | 125 | let parent_enum = src.value.parent_enum(); |
176 | let src_enum = InFile { file_id: src.file_id, value: parent_enum }; | 126 | let src_enum = InFile { file_id: src.file_id, value: parent_enum }; |
177 | let variants = Enum::from_source(db, src_enum)?.variants(db); | 127 | let parent_enum = Enum::from_source(db, src_enum)?; |
178 | variants.into_iter().find(|v| same_source(&v.source(db), &src)) | 128 | parent_enum.id.child_from_source(db, src).map(EnumVariant::from) |
179 | } | 129 | } |
180 | } | 130 | } |
181 | 131 | ||
182 | impl FromSource for StructField { | 132 | impl FromSource for StructField { |
183 | type Ast = FieldSource; | 133 | type Ast = FieldSource; |
184 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { | 134 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { |
185 | let variant_def: VariantDef = match src.value { | 135 | let variant_id: VariantId = match src.value { |
186 | FieldSource::Named(ref field) => { | 136 | FieldSource::Named(ref field) => { |
187 | let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?; | 137 | let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?; |
188 | let src = InFile { file_id: src.file_id, value }; | 138 | let src = InFile { file_id: src.file_id, value }; |
189 | let def = Struct::from_source(db, src)?; | 139 | let def = Struct::from_source(db, src)?; |
190 | VariantDef::from(def) | 140 | def.id.into() |
191 | } | 141 | } |
192 | FieldSource::Pos(ref field) => { | 142 | FieldSource::Pos(ref field) => { |
193 | let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?; | 143 | let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?; |
194 | let src = InFile { file_id: src.file_id, value }; | 144 | let src = InFile { file_id: src.file_id, value }; |
195 | let def = EnumVariant::from_source(db, src)?; | 145 | let def = EnumVariant::from_source(db, src)?; |
196 | VariantDef::from(def) | 146 | EnumVariantId::from(def).into() |
197 | } | 147 | } |
198 | }; | 148 | }; |
199 | variant_def | 149 | let src = src.map(|field_source| match field_source { |
200 | .variant_data(db) | 150 | FieldSource::Pos(it) => Either::Left(it), |
201 | .fields() | 151 | FieldSource::Named(it) => Either::Right(it), |
202 | .iter() | 152 | }); |
203 | .map(|(id, _)| StructField { parent: variant_def, id }) | 153 | variant_id.child_from_source(db, src).map(StructField::from) |
204 | .find(|f| f.source(db) == src) | ||
205 | } | 154 | } |
206 | } | 155 | } |
207 | 156 | ||
@@ -314,13 +263,3 @@ impl Container { | |||
314 | Some(Container::Module(c)) | 263 | Some(Container::Module(c)) |
315 | } | 264 | } |
316 | } | 265 | } |
317 | |||
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) | ||
326 | } | ||