aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/semantics.rs116
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.
84pub struct Semantics<'db, DB> { 84pub 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
89pub struct SemanticsImpl<'db> { 89pub struct SemanticsImpl<'db> {
@@ -101,19 +101,22 @@ impl<DB> fmt::Debug for Semantics<'_, DB> {
101impl<'db, DB: HirDatabase> Semantics<'db, DB> { 101impl<'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!(