diff options
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/lib.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 29 |
2 files changed, 40 insertions, 1 deletions
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 9f59d590c..713d45f48 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -4,6 +4,18 @@ | |||
4 | //! The principal difference between HIR and syntax trees is that HIR is bound | 4 | //! The principal difference between HIR and syntax trees is that HIR is bound |
5 | //! to a particular crate instance. That is, it has cfg flags and features | 5 | //! to a particular crate instance. That is, it has cfg flags and features |
6 | //! applied. So, the relation between syntax and HIR is many-to-one. | 6 | //! applied. So, the relation between syntax and HIR is many-to-one. |
7 | //! | ||
8 | //! HIR is the public API of the all of the compiler logic above syntax trees. | ||
9 | //! It is written in "OO" style. Each type is self contained (as in, it knows it's | ||
10 | //! parents and full context). It should be "clean code". | ||
11 | //! | ||
12 | //! `ra_hir_*` crates are the implementation of the compiler logic. | ||
13 | //! They are written in "ECS" style, with relatively little abstractions. | ||
14 | //! Many types are not self-contained, and explicitly use local indexes, arenas, etc. | ||
15 | //! | ||
16 | //! `ra_hir` is what insulates the "we don't know how to actually write an incremental compiler" | ||
17 | //! from the ide with completions, hovers, etc. It is a (soft, internal) boundary: | ||
18 | //! https://www.tedinski.com/2018/02/06/system-boundaries.html. | ||
7 | 19 | ||
8 | #![recursion_limit = "512"] | 20 | #![recursion_limit = "512"] |
9 | 21 | ||
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 55e634528..d982f6ffa 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -12,7 +12,8 @@ use hir_expand::ExpansionInfo; | |||
12 | use ra_db::{FileId, FileRange}; | 12 | use ra_db::{FileId, FileRange}; |
13 | use ra_prof::profile; | 13 | use ra_prof::profile; |
14 | use ra_syntax::{ | 14 | use ra_syntax::{ |
15 | algo::skip_trivia_token, ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextUnit, | 15 | algo::{find_node_at_offset, skip_trivia_token}, |
16 | ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextUnit, | ||
16 | }; | 17 | }; |
17 | use rustc_hash::{FxHashMap, FxHashSet}; | 18 | use rustc_hash::{FxHashMap, FxHashSet}; |
18 | 19 | ||
@@ -108,6 +109,17 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
108 | token.value | 109 | token.value |
109 | } | 110 | } |
110 | 111 | ||
112 | pub fn descend_node_at_offset<N: ast::AstNode>( | ||
113 | &self, | ||
114 | node: &SyntaxNode, | ||
115 | offset: TextUnit, | ||
116 | ) -> Option<N> { | ||
117 | // Handle macro token cases | ||
118 | node.token_at_offset(offset) | ||
119 | .map(|token| self.descend_into_macros(token)) | ||
120 | .find_map(|it| self.ancestors_with_macros(it.parent()).find_map(N::cast)) | ||
121 | } | ||
122 | |||
111 | pub fn original_range(&self, node: &SyntaxNode) -> FileRange { | 123 | pub fn original_range(&self, node: &SyntaxNode) -> FileRange { |
112 | let node = self.find_file(node.clone()); | 124 | let node = self.find_file(node.clone()); |
113 | original_range(self.db, node.as_ref()) | 125 | original_range(self.db, node.as_ref()) |
@@ -129,6 +141,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
129 | .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) | 141 | .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) |
130 | } | 142 | } |
131 | 143 | ||
144 | /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*, | ||
145 | /// search up until it is of the target AstNode type | ||
132 | pub fn find_node_at_offset_with_macros<N: AstNode>( | 146 | pub fn find_node_at_offset_with_macros<N: AstNode>( |
133 | &self, | 147 | &self, |
134 | node: &SyntaxNode, | 148 | node: &SyntaxNode, |
@@ -137,6 +151,19 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
137 | self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) | 151 | self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) |
138 | } | 152 | } |
139 | 153 | ||
154 | /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*, | ||
155 | /// descend it and find again | ||
156 | pub fn find_node_at_offset_with_descend<N: AstNode>( | ||
157 | &self, | ||
158 | node: &SyntaxNode, | ||
159 | offset: TextUnit, | ||
160 | ) -> Option<N> { | ||
161 | if let Some(it) = find_node_at_offset(&node, offset) { | ||
162 | return Some(it); | ||
163 | } | ||
164 | self.descend_node_at_offset(&node, offset) | ||
165 | } | ||
166 | |||
140 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { | 167 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { |
141 | self.analyze(expr.syntax()).type_of(self.db, &expr) | 168 | self.analyze(expr.syntax()).type_of(self.db, &expr) |
142 | } | 169 | } |