diff options
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 116 |
1 files changed, 47 insertions, 69 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index fbea9ad57..3d78f71c1 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -83,7 +83,7 @@ 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>, | 86 | imp: SemanticsImpl<'db>, |
87 | } | 87 | } |
88 | 88 | ||
89 | pub struct SemanticsImpl<'db> { | 89 | pub struct SemanticsImpl<'db> { |
@@ -101,19 +101,22 @@ impl<DB> fmt::Debug for Semantics<'_, DB> { | |||
101 | impl<'db, DB: HirDatabase> Semantics<'db, DB> { | 101 | impl<'db, DB: HirDatabase> Semantics<'db, DB> { |
102 | pub fn new(db: &DB) -> Semantics<DB> { | 102 | pub fn new(db: &DB) -> Semantics<DB> { |
103 | let impl_ = SemanticsImpl::new(db); | 103 | let impl_ = SemanticsImpl::new(db); |
104 | Semantics { db, impl_ } | 104 | Semantics { db, imp: impl_ } |
105 | } | 105 | } |
106 | 106 | ||
107 | pub fn parse(&self, file_id: FileId) -> ast::SourceFile { | 107 | pub fn parse(&self, file_id: FileId) -> ast::SourceFile { |
108 | self.impl_.parse(file_id) | 108 | self.imp.parse(file_id) |
109 | } | 109 | } |
110 | 110 | ||
111 | pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST { | 111 | pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST { |
112 | self.impl_.ast(d) | 112 | let file_id = d.source().file_id; |
113 | let root = self.db.parse_or_expand(file_id).unwrap(); | ||
114 | self.imp.cache(root, file_id); | ||
115 | d.ast(self.db.upcast()) | ||
113 | } | 116 | } |
114 | 117 | ||
115 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { | 118 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { |
116 | self.impl_.expand(macro_call) | 119 | self.imp.expand(macro_call) |
117 | } | 120 | } |
118 | 121 | ||
119 | pub fn expand_hypothetical( | 122 | pub fn expand_hypothetical( |
@@ -122,11 +125,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
122 | hypothetical_args: &ast::TokenTree, | 125 | hypothetical_args: &ast::TokenTree, |
123 | token_to_map: SyntaxToken, | 126 | token_to_map: SyntaxToken, |
124 | ) -> Option<(SyntaxNode, SyntaxToken)> { | 127 | ) -> Option<(SyntaxNode, SyntaxToken)> { |
125 | self.impl_.expand_hypothetical(actual_macro_call, hypothetical_args, token_to_map) | 128 | self.imp.expand_hypothetical(actual_macro_call, hypothetical_args, token_to_map) |
126 | } | 129 | } |
127 | 130 | ||
128 | pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { | 131 | pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { |
129 | self.impl_.descend_into_macros(token) | 132 | self.imp.descend_into_macros(token) |
130 | } | 133 | } |
131 | 134 | ||
132 | pub fn descend_node_at_offset<N: ast::AstNode>( | 135 | pub fn descend_node_at_offset<N: ast::AstNode>( |
@@ -134,19 +137,19 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
134 | node: &SyntaxNode, | 137 | node: &SyntaxNode, |
135 | offset: TextSize, | 138 | offset: TextSize, |
136 | ) -> Option<N> { | 139 | ) -> Option<N> { |
137 | self.impl_.descend_node_at_offset(node, offset) | 140 | self.imp.descend_node_at_offset(node, offset).find_map(N::cast) |
138 | } | 141 | } |
139 | 142 | ||
140 | pub fn original_range(&self, node: &SyntaxNode) -> FileRange { | 143 | pub fn original_range(&self, node: &SyntaxNode) -> FileRange { |
141 | self.impl_.original_range(node) | 144 | self.imp.original_range(node) |
142 | } | 145 | } |
143 | 146 | ||
144 | pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { | 147 | pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { |
145 | self.impl_.diagnostics_range(diagnostics) | 148 | self.imp.diagnostics_range(diagnostics) |
146 | } | 149 | } |
147 | 150 | ||
148 | pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { | 151 | pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { |
149 | self.impl_.ancestors_with_macros(node) | 152 | self.imp.ancestors_with_macros(node) |
150 | } | 153 | } |
151 | 154 | ||
152 | pub fn ancestors_at_offset_with_macros( | 155 | pub fn ancestors_at_offset_with_macros( |
@@ -154,7 +157,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
154 | node: &SyntaxNode, | 157 | node: &SyntaxNode, |
155 | offset: TextSize, | 158 | offset: TextSize, |
156 | ) -> impl Iterator<Item = SyntaxNode> + '_ { | 159 | ) -> impl Iterator<Item = SyntaxNode> + '_ { |
157 | self.impl_.ancestors_at_offset_with_macros(node, offset) | 160 | self.imp.ancestors_at_offset_with_macros(node, offset) |
158 | } | 161 | } |
159 | 162 | ||
160 | /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*, | 163 | /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*, |
@@ -164,7 +167,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
164 | node: &SyntaxNode, | 167 | node: &SyntaxNode, |
165 | offset: TextSize, | 168 | offset: TextSize, |
166 | ) -> Option<N> { | 169 | ) -> Option<N> { |
167 | self.impl_.find_node_at_offset_with_macros(node, offset) | 170 | self.imp.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) |
168 | } | 171 | } |
169 | 172 | ||
170 | /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*, | 173 | /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*, |
@@ -174,86 +177,91 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
174 | node: &SyntaxNode, | 177 | node: &SyntaxNode, |
175 | offset: TextSize, | 178 | offset: TextSize, |
176 | ) -> Option<N> { | 179 | ) -> Option<N> { |
177 | self.impl_.find_node_at_offset_with_descend(node, offset) | 180 | if let Some(it) = find_node_at_offset(&node, offset) { |
181 | return Some(it); | ||
182 | } | ||
183 | |||
184 | self.imp.descend_node_at_offset(node, offset).find_map(N::cast) | ||
178 | } | 185 | } |
179 | 186 | ||
180 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { | 187 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { |
181 | self.impl_.type_of_expr(expr) | 188 | self.imp.type_of_expr(expr) |
182 | } | 189 | } |
183 | 190 | ||
184 | pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> { | 191 | pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> { |
185 | self.impl_.type_of_pat(pat) | 192 | self.imp.type_of_pat(pat) |
186 | } | 193 | } |
187 | 194 | ||
188 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | 195 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { |
189 | self.impl_.resolve_method_call(call) | 196 | self.imp.resolve_method_call(call) |
190 | } | 197 | } |
191 | 198 | ||
192 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { | 199 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { |
193 | self.impl_.resolve_field(field) | 200 | self.imp.resolve_field(field) |
194 | } | 201 | } |
195 | 202 | ||
196 | pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<(Field, Option<Local>)> { | 203 | pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<(Field, Option<Local>)> { |
197 | self.impl_.resolve_record_field(field) | 204 | self.imp.resolve_record_field(field) |
198 | } | 205 | } |
199 | 206 | ||
200 | pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<Field> { | 207 | pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<Field> { |
201 | self.impl_.resolve_record_field_pat(field) | 208 | self.imp.resolve_record_field_pat(field) |
202 | } | 209 | } |
203 | 210 | ||
204 | pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> { | 211 | pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> { |
205 | self.impl_.resolve_macro_call(macro_call) | 212 | self.imp.resolve_macro_call(macro_call) |
206 | } | 213 | } |
207 | 214 | ||
208 | pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> { | 215 | pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> { |
209 | self.impl_.resolve_path(path) | 216 | self.imp.resolve_path(path) |
210 | } | 217 | } |
211 | 218 | ||
212 | pub fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option<VariantId> { | 219 | pub fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option<VariantId> { |
213 | self.impl_.resolve_variant(record_lit) | 220 | self.imp.resolve_variant(record_lit) |
214 | } | 221 | } |
215 | 222 | ||
216 | pub fn lower_path(&self, path: &ast::Path) -> Option<Path> { | 223 | pub fn lower_path(&self, path: &ast::Path) -> Option<Path> { |
217 | self.impl_.lower_path(path) | 224 | self.imp.lower_path(path) |
218 | } | 225 | } |
219 | 226 | ||
220 | pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> { | 227 | pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> { |
221 | self.impl_.resolve_bind_pat_to_const(pat) | 228 | self.imp.resolve_bind_pat_to_const(pat) |
222 | } | 229 | } |
223 | 230 | ||
224 | // FIXME: use this instead? | 231 | // FIXME: use this instead? |
225 | // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>; | 232 | // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>; |
226 | 233 | ||
227 | pub fn record_literal_missing_fields(&self, literal: &ast::RecordLit) -> Vec<(Field, Type)> { | 234 | pub fn record_literal_missing_fields(&self, literal: &ast::RecordLit) -> Vec<(Field, Type)> { |
228 | self.impl_.record_literal_missing_fields(literal) | 235 | self.imp.record_literal_missing_fields(literal) |
229 | } | 236 | } |
230 | 237 | ||
231 | pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> { | 238 | pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> { |
232 | self.impl_.record_pattern_missing_fields(pattern) | 239 | self.imp.record_pattern_missing_fields(pattern) |
233 | } | 240 | } |
234 | 241 | ||
235 | pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> { | 242 | pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> { |
236 | self.impl_.to_def(src) | 243 | let src = self.imp.find_file(src.syntax().clone()).with_value(src).cloned(); |
244 | T::to_def(&self.imp, src) | ||
237 | } | 245 | } |
238 | 246 | ||
239 | pub fn to_module_def(&self, file: FileId) -> Option<Module> { | 247 | pub fn to_module_def(&self, file: FileId) -> Option<Module> { |
240 | self.impl_.to_module_def(file) | 248 | self.imp.to_module_def(file) |
241 | } | 249 | } |
242 | 250 | ||
243 | pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> { | 251 | pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> { |
244 | self.impl_.scope(node) | 252 | self.imp.scope(node) |
245 | } | 253 | } |
246 | 254 | ||
247 | pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> { | 255 | pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> { |
248 | self.impl_.scope_at_offset(node, offset) | 256 | self.imp.scope_at_offset(node, offset) |
249 | } | 257 | } |
250 | 258 | ||
251 | pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { | 259 | pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> { |
252 | self.impl_.scope_for_def(def) | 260 | self.imp.scope_for_def(def) |
253 | } | 261 | } |
254 | 262 | ||
255 | pub fn assert_contains_node(&self, node: &SyntaxNode) { | 263 | pub fn assert_contains_node(&self, node: &SyntaxNode) { |
256 | self.impl_.assert_contains_node(node) | 264 | self.imp.assert_contains_node(node) |
257 | } | 265 | } |
258 | } | 266 | } |
259 | 267 | ||
@@ -268,13 +276,6 @@ impl<'db> SemanticsImpl<'db> { | |||
268 | tree | 276 | tree |
269 | } | 277 | } |
270 | 278 | ||
271 | pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST { | ||
272 | let file_id = d.source().file_id; | ||
273 | let root = self.db.parse_or_expand(file_id).unwrap(); | ||
274 | self.cache(root, file_id); | ||
275 | d.ast(self.db.upcast()) | ||
276 | } | ||
277 | |||
278 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { | 279 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { |
279 | let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); | 280 | let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); |
280 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); | 281 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); |
@@ -329,15 +330,16 @@ impl<'db> SemanticsImpl<'db> { | |||
329 | token.value | 330 | token.value |
330 | } | 331 | } |
331 | 332 | ||
332 | pub fn descend_node_at_offset<N: ast::AstNode>( | 333 | pub fn descend_node_at_offset( |
333 | &self, | 334 | &self, |
334 | node: &SyntaxNode, | 335 | node: &SyntaxNode, |
335 | offset: TextSize, | 336 | offset: TextSize, |
336 | ) -> Option<N> { | 337 | ) -> impl Iterator<Item = SyntaxNode> + '_ { |
337 | // Handle macro token cases | 338 | // Handle macro token cases |
338 | node.token_at_offset(offset) | 339 | node.token_at_offset(offset) |
339 | .map(|token| self.descend_into_macros(token)) | 340 | .map(|token| self.descend_into_macros(token)) |
340 | .find_map(|it| self.ancestors_with_macros(it.parent()).find_map(N::cast)) | 341 | .map(|it| self.ancestors_with_macros(it.parent())) |
342 | .flatten() | ||
341 | } | 343 | } |
342 | 344 | ||
343 | pub fn original_range(&self, node: &SyntaxNode) -> FileRange { | 345 | pub fn original_range(&self, node: &SyntaxNode) -> FileRange { |
@@ -367,25 +369,6 @@ impl<'db> SemanticsImpl<'db> { | |||
367 | .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) | 369 | .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) |
368 | } | 370 | } |
369 | 371 | ||
370 | pub fn find_node_at_offset_with_macros<N: AstNode>( | ||
371 | &self, | ||
372 | node: &SyntaxNode, | ||
373 | offset: TextSize, | ||
374 | ) -> Option<N> { | ||
375 | self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) | ||
376 | } | ||
377 | |||
378 | pub fn find_node_at_offset_with_descend<N: AstNode>( | ||
379 | &self, | ||
380 | node: &SyntaxNode, | ||
381 | offset: TextSize, | ||
382 | ) -> Option<N> { | ||
383 | if let Some(it) = find_node_at_offset(&node, offset) { | ||
384 | return Some(it); | ||
385 | } | ||
386 | self.descend_node_at_offset(&node, offset) | ||
387 | } | ||
388 | |||
389 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { | 372 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { |
390 | self.analyze(expr.syntax()).type_of(self.db, &expr) | 373 | self.analyze(expr.syntax()).type_of(self.db, &expr) |
391 | } | 374 | } |
@@ -445,11 +428,6 @@ impl<'db> SemanticsImpl<'db> { | |||
445 | .unwrap_or_default() | 428 | .unwrap_or_default() |
446 | } | 429 | } |
447 | 430 | ||
448 | pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> { | ||
449 | let src = self.find_file(src.syntax().clone()).with_value(src).cloned(); | ||
450 | T::to_def(self, src) | ||
451 | } | ||
452 | |||
453 | fn with_ctx<F: FnOnce(&mut SourceToDefCtx) -> T, T>(&self, f: F) -> T { | 431 | fn with_ctx<F: FnOnce(&mut SourceToDefCtx) -> T, T>(&self, f: F) -> T { |
454 | let mut cache = self.s2d_cache.borrow_mut(); | 432 | let mut cache = self.s2d_cache.borrow_mut(); |
455 | let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache }; | 433 | let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache }; |
@@ -504,7 +482,7 @@ impl<'db> SemanticsImpl<'db> { | |||
504 | SourceAnalyzer::new_for_resolver(resolver, src) | 482 | SourceAnalyzer::new_for_resolver(resolver, src) |
505 | } | 483 | } |
506 | 484 | ||
507 | fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) { | 485 | pub fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) { |
508 | assert!(root_node.parent().is_none()); | 486 | assert!(root_node.parent().is_none()); |
509 | let mut cache = self.cache.borrow_mut(); | 487 | let mut cache = self.cache.borrow_mut(); |
510 | let prev = cache.insert(root_node, file_id); | 488 | let prev = cache.insert(root_node, file_id); |
@@ -520,7 +498,7 @@ impl<'db> SemanticsImpl<'db> { | |||
520 | cache.get(root_node).copied() | 498 | cache.get(root_node).copied() |
521 | } | 499 | } |
522 | 500 | ||
523 | fn find_file(&self, node: SyntaxNode) -> InFile<SyntaxNode> { | 501 | pub fn find_file(&self, node: SyntaxNode) -> InFile<SyntaxNode> { |
524 | let root_node = find_root(&node); | 502 | let root_node = find_root(&node); |
525 | let file_id = self.lookup(&root_node).unwrap_or_else(|| { | 503 | let file_id = self.lookup(&root_node).unwrap_or_else(|| { |
526 | panic!( | 504 | panic!( |