aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/semantics.rs209
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.
84pub struct Semantics<'db, DB> { 84pub struct Semantics<'db, DB> {
85 pub db: &'db DB, 85 pub db: &'db DB,
86 impl_: SemanticsImpl<'db>,
87}
88
89pub 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
96impl<'db, DB: HirDatabase> Semantics<'db, DB> { 101impl<'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
260impl<'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(&macro_call))?; 319 let file_id = sa.expand(self.db, token.with_value(&macro_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> {
382pub trait ToDef: AstNode + Clone { 545pub 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
388macro_rules! to_def_impls { 551macro_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 }