diff options
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 209 |
1 files changed, 186 insertions, 23 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 810c49d6f..fbea9ad57 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -83,6 +83,11 @@ impl PathResolution { | |||
83 | /// Primary API to get semantic information, like types, from syntax trees. | 83 | /// Primary API to get semantic information, like types, from syntax trees. |
84 | pub struct Semantics<'db, DB> { | 84 | pub struct Semantics<'db, DB> { |
85 | pub db: &'db DB, | 85 | pub db: &'db DB, |
86 | impl_: SemanticsImpl<'db>, | ||
87 | } | ||
88 | |||
89 | pub struct SemanticsImpl<'db> { | ||
90 | pub db: &'db dyn HirDatabase, | ||
86 | s2d_cache: RefCell<SourceToDefCache>, | 91 | s2d_cache: RefCell<SourceToDefCache>, |
87 | cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>, | 92 | cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>, |
88 | } | 93 | } |
@@ -95,7 +100,166 @@ impl<DB> fmt::Debug for Semantics<'_, DB> { | |||
95 | 100 | ||
96 | impl<'db, DB: HirDatabase> Semantics<'db, DB> { | 101 | impl<'db, DB: HirDatabase> Semantics<'db, DB> { |
97 | pub fn new(db: &DB) -> Semantics<DB> { | 102 | pub fn new(db: &DB) -> Semantics<DB> { |
98 | Semantics { db, s2d_cache: Default::default(), cache: Default::default() } | 103 | let impl_ = SemanticsImpl::new(db); |
104 | Semantics { db, impl_ } | ||
105 | } | ||
106 | |||
107 | pub fn parse(&self, file_id: FileId) -> ast::SourceFile { | ||
108 | self.impl_.parse(file_id) | ||
109 | } | ||
110 | |||
111 | pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST { | ||
112 | self.impl_.ast(d) | ||
113 | } | ||
114 | |||
115 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { | ||
116 | self.impl_.expand(macro_call) | ||
117 | } | ||
118 | |||
119 | pub fn expand_hypothetical( | ||
120 | &self, | ||
121 | actual_macro_call: &ast::MacroCall, | ||
122 | hypothetical_args: &ast::TokenTree, | ||
123 | token_to_map: SyntaxToken, | ||
124 | ) -> Option<(SyntaxNode, SyntaxToken)> { | ||
125 | self.impl_.expand_hypothetical(actual_macro_call, hypothetical_args, token_to_map) | ||
126 | } | ||
127 | |||
128 | pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { | ||
129 | self.impl_.descend_into_macros(token) | ||
130 | } | ||
131 | |||
132 | pub fn descend_node_at_offset<N: ast::AstNode>( | ||
133 | &self, | ||
134 | node: &SyntaxNode, | ||
135 | offset: TextSize, | ||
136 | ) -> Option<N> { | ||
137 | self.impl_.descend_node_at_offset(node, offset) | ||
138 | } | ||
139 | |||
140 | pub fn original_range(&self, node: &SyntaxNode) -> FileRange { | ||
141 | self.impl_.original_range(node) | ||
142 | } | ||
143 | |||
144 | pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { | ||
145 | self.impl_.diagnostics_range(diagnostics) | ||
146 | } | ||
147 | |||
148 | pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { | ||
149 | self.impl_.ancestors_with_macros(node) | ||
150 | } | ||
151 | |||
152 | pub fn ancestors_at_offset_with_macros( | ||
153 | &self, | ||
154 | node: &SyntaxNode, | ||
155 | offset: TextSize, | ||
156 | ) -> impl Iterator<Item = SyntaxNode> + '_ { | ||
157 | self.impl_.ancestors_at_offset_with_macros(node, offset) | ||
158 | } | ||
159 | |||
160 | /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*, | ||
161 | /// search up until it is of the target AstNode type | ||
162 | pub fn find_node_at_offset_with_macros<N: AstNode>( | ||
163 | &self, | ||
164 | node: &SyntaxNode, | ||
165 | offset: TextSize, | ||
166 | ) -> Option<N> { | ||
167 | self.impl_.find_node_at_offset_with_macros(node, offset) | ||
168 | } | ||
169 | |||
170 | /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*, | ||
171 | /// descend it and find again | ||
172 | pub fn find_node_at_offset_with_descend<N: AstNode>( | ||
173 | &self, | ||
174 | node: &SyntaxNode, | ||
175 | offset: TextSize, | ||
176 | ) -> Option<N> { | ||
177 | self.impl_.find_node_at_offset_with_descend(node, offset) | ||
178 | } | ||
179 | |||
180 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { | ||
181 | self.impl_.type_of_expr(expr) | ||
182 | } | ||
183 | |||
184 | pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> { | ||
185 | self.impl_.type_of_pat(pat) | ||
186 | } | ||
187 | |||
188 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | ||
189 | self.impl_.resolve_method_call(call) | ||
190 | } | ||
191 | |||
192 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { | ||
193 | self.impl_.resolve_field(field) | ||
194 | } | ||
195 | |||
196 | pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<(Field, Option<Local>)> { | ||
197 | self.impl_.resolve_record_field(field) | ||
198 | } | ||
199 | |||
200 | pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<Field> { | ||
201 | self.impl_.resolve_record_field_pat(field) | ||
202 | } | ||
203 | |||
204 | pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> { | ||
205 | self.impl_.resolve_macro_call(macro_call) | ||
206 | } | ||
207 | |||
208 | pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> { | ||
209 | self.impl_.resolve_path(path) | ||
210 | } | ||
211 | |||
212 | pub fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option<VariantId> { | ||
213 | self.impl_.resolve_variant(record_lit) | ||
214 | } | ||
215 | |||
216 | pub fn lower_path(&self, path: &ast::Path) -> Option<Path> { | ||
217 | self.impl_.lower_path(path) | ||
218 | } | ||
219 | |||
220 | pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> { | ||
221 | self.impl_.resolve_bind_pat_to_const(pat) | ||
222 | } | ||
223 | |||
224 | // FIXME: use this instead? | ||
225 | // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>; | ||
226 | |||
227 | pub fn record_literal_missing_fields(&self, literal: &ast::RecordLit) -> Vec<(Field, Type)> { | ||
228 | self.impl_.record_literal_missing_fields(literal) | ||
229 | } | ||
230 | |||
231 | pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> { | ||
232 | self.impl_.record_pattern_missing_fields(pattern) | ||
233 | } | ||
234 | |||
235 | pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> { | ||
236 | self.impl_.to_def(src) | ||
237 | } | ||
238 | |||
239 | pub fn to_module_def(&self, file: FileId) -> Option<Module> { | ||
240 | self.impl_.to_module_def(file) | ||
241 | } | ||
242 | |||
243 | pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> { | ||
244 | self.impl_.scope(node) | ||
245 | } | ||
246 | |||
247 | pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> { | ||
248 | self.impl_.scope_at_offset(node, offset) | ||
249 | } | ||
250 | |||
251 | pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { | ||
252 | self.impl_.scope_for_def(def) | ||
253 | } | ||
254 | |||
255 | pub fn assert_contains_node(&self, node: &SyntaxNode) { | ||
256 | self.impl_.assert_contains_node(node) | ||
257 | } | ||
258 | } | ||
259 | |||
260 | impl<'db> SemanticsImpl<'db> { | ||
261 | pub fn new(db: &'db dyn HirDatabase) -> Self { | ||
262 | Self { db, s2d_cache: Default::default(), cache: Default::default() } | ||
99 | } | 263 | } |
100 | 264 | ||
101 | pub fn parse(&self, file_id: FileId) -> ast::SourceFile { | 265 | pub fn parse(&self, file_id: FileId) -> ast::SourceFile { |
@@ -108,7 +272,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
108 | let file_id = d.source().file_id; | 272 | let file_id = d.source().file_id; |
109 | let root = self.db.parse_or_expand(file_id).unwrap(); | 273 | let root = self.db.parse_or_expand(file_id).unwrap(); |
110 | self.cache(root, file_id); | 274 | self.cache(root, file_id); |
111 | d.ast(self.db) | 275 | d.ast(self.db.upcast()) |
112 | } | 276 | } |
113 | 277 | ||
114 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { | 278 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { |
@@ -130,9 +294,15 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
130 | self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); | 294 | self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); |
131 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); | 295 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); |
132 | let krate = sa.resolver.krate()?; | 296 | let krate = sa.resolver.krate()?; |
133 | let macro_call_id = macro_call | 297 | let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { |
134 | .as_call_id(self.db, krate, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; | 298 | sa.resolver.resolve_path_as_macro(self.db.upcast(), &path) |
135 | hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map) | 299 | })?; |
300 | hir_expand::db::expand_hypothetical( | ||
301 | self.db.upcast(), | ||
302 | macro_call_id, | ||
303 | hypothetical_args, | ||
304 | token_to_map, | ||
305 | ) | ||
136 | } | 306 | } |
137 | 307 | ||
138 | pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { | 308 | pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { |
@@ -147,7 +317,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
147 | return None; | 317 | return None; |
148 | } | 318 | } |
149 | let file_id = sa.expand(self.db, token.with_value(¯o_call))?; | 319 | let file_id = sa.expand(self.db, token.with_value(¯o_call))?; |
150 | let token = file_id.expansion_info(self.db)?.map_token_down(token.as_ref())?; | 320 | let token = file_id.expansion_info(self.db.upcast())?.map_token_down(token.as_ref())?; |
151 | 321 | ||
152 | self.cache(find_root(&token.value.parent()), token.file_id); | 322 | self.cache(find_root(&token.value.parent()), token.file_id); |
153 | 323 | ||
@@ -184,7 +354,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
184 | 354 | ||
185 | pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { | 355 | pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { |
186 | let node = self.find_file(node); | 356 | let node = self.find_file(node); |
187 | node.ancestors_with_macros(self.db).map(|it| it.value) | 357 | node.ancestors_with_macros(self.db.upcast()).map(|it| it.value) |
188 | } | 358 | } |
189 | 359 | ||
190 | pub fn ancestors_at_offset_with_macros( | 360 | pub fn ancestors_at_offset_with_macros( |
@@ -197,8 +367,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
197 | .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) | 367 | .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) |
198 | } | 368 | } |
199 | 369 | ||
200 | /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*, | ||
201 | /// search up until it is of the target AstNode type | ||
202 | pub fn find_node_at_offset_with_macros<N: AstNode>( | 370 | pub fn find_node_at_offset_with_macros<N: AstNode>( |
203 | &self, | 371 | &self, |
204 | node: &SyntaxNode, | 372 | node: &SyntaxNode, |
@@ -207,8 +375,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
207 | self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) | 375 | self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) |
208 | } | 376 | } |
209 | 377 | ||
210 | /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*, | ||
211 | /// descend it and find again | ||
212 | pub fn find_node_at_offset_with_descend<N: AstNode>( | 378 | pub fn find_node_at_offset_with_descend<N: AstNode>( |
213 | &self, | 379 | &self, |
214 | node: &SyntaxNode, | 380 | node: &SyntaxNode, |
@@ -267,9 +433,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
267 | self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat) | 433 | self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat) |
268 | } | 434 | } |
269 | 435 | ||
270 | // FIXME: use this instead? | ||
271 | // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>; | ||
272 | |||
273 | pub fn record_literal_missing_fields(&self, literal: &ast::RecordLit) -> Vec<(Field, Type)> { | 436 | pub fn record_literal_missing_fields(&self, literal: &ast::RecordLit) -> Vec<(Field, Type)> { |
274 | self.analyze(literal.syntax()) | 437 | self.analyze(literal.syntax()) |
275 | .record_literal_missing_fields(self.db, literal) | 438 | .record_literal_missing_fields(self.db, literal) |
@@ -310,7 +473,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
310 | } | 473 | } |
311 | 474 | ||
312 | pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { | 475 | pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { |
313 | let resolver = def.id.resolver(self.db); | 476 | let resolver = def.id.resolver(self.db.upcast()); |
314 | SemanticsScope { db: self.db, resolver } | 477 | SemanticsScope { db: self.db, resolver } |
315 | } | 478 | } |
316 | 479 | ||
@@ -331,12 +494,12 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
331 | ChildContainer::DefWithBodyId(def) => { | 494 | ChildContainer::DefWithBodyId(def) => { |
332 | return SourceAnalyzer::new_for_body(self.db, def, src, offset) | 495 | return SourceAnalyzer::new_for_body(self.db, def, src, offset) |
333 | } | 496 | } |
334 | ChildContainer::TraitId(it) => it.resolver(self.db), | 497 | ChildContainer::TraitId(it) => it.resolver(self.db.upcast()), |
335 | ChildContainer::ImplId(it) => it.resolver(self.db), | 498 | ChildContainer::ImplId(it) => it.resolver(self.db.upcast()), |
336 | ChildContainer::ModuleId(it) => it.resolver(self.db), | 499 | ChildContainer::ModuleId(it) => it.resolver(self.db.upcast()), |
337 | ChildContainer::EnumId(it) => it.resolver(self.db), | 500 | ChildContainer::EnumId(it) => it.resolver(self.db.upcast()), |
338 | ChildContainer::VariantId(it) => it.resolver(self.db), | 501 | ChildContainer::VariantId(it) => it.resolver(self.db.upcast()), |
339 | ChildContainer::GenericDefId(it) => it.resolver(self.db), | 502 | ChildContainer::GenericDefId(it) => it.resolver(self.db.upcast()), |
340 | }; | 503 | }; |
341 | SourceAnalyzer::new_for_resolver(resolver, src) | 504 | SourceAnalyzer::new_for_resolver(resolver, src) |
342 | } | 505 | } |
@@ -382,14 +545,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
382 | pub trait ToDef: AstNode + Clone { | 545 | pub trait ToDef: AstNode + Clone { |
383 | type Def; | 546 | type Def; |
384 | 547 | ||
385 | fn to_def<DB: HirDatabase>(sema: &Semantics<DB>, src: InFile<Self>) -> Option<Self::Def>; | 548 | fn to_def(sema: &SemanticsImpl, src: InFile<Self>) -> Option<Self::Def>; |
386 | } | 549 | } |
387 | 550 | ||
388 | macro_rules! to_def_impls { | 551 | macro_rules! to_def_impls { |
389 | ($(($def:path, $ast:path, $meth:ident)),* ,) => {$( | 552 | ($(($def:path, $ast:path, $meth:ident)),* ,) => {$( |
390 | impl ToDef for $ast { | 553 | impl ToDef for $ast { |
391 | type Def = $def; | 554 | type Def = $def; |
392 | fn to_def<DB: HirDatabase>(sema: &Semantics<DB>, src: InFile<Self>) -> Option<Self::Def> { | 555 | fn to_def(sema: &SemanticsImpl, src: InFile<Self>) -> Option<Self::Def> { |
393 | sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from) | 556 | sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from) |
394 | } | 557 | } |
395 | } | 558 | } |