diff options
author | Aleksey Kladov <[email protected]> | 2020-02-18 17:35:10 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-02-26 11:55:50 +0000 |
commit | c3a4c4429de83450654795534e64e878a774a088 (patch) | |
tree | 12d89798f61b276f8bd640db07276a7d4e92b1c2 /crates/ra_ide/src/expand.rs | |
parent | 04deae3dba7c9b7054f7a1d64e4b93a05aecc132 (diff) |
Refactor primary IDE API
This introduces the new type -- Semantics.
Semantics maps SyntaxNodes to various semantic info, such as type,
name resolution or macro expansions.
To do so, Semantics maintains a HashMap which maps every node it saw
to the file from which the node originated. This is enough to get all
the necessary hir bits just from syntax.
Diffstat (limited to 'crates/ra_ide/src/expand.rs')
-rw-r--r-- | crates/ra_ide/src/expand.rs | 102 |
1 files changed, 0 insertions, 102 deletions
diff --git a/crates/ra_ide/src/expand.rs b/crates/ra_ide/src/expand.rs deleted file mode 100644 index 9f3aaa3a3..000000000 --- a/crates/ra_ide/src/expand.rs +++ /dev/null | |||
@@ -1,102 +0,0 @@ | |||
1 | //! Utilities to work with files, produced by macros. | ||
2 | use std::iter::successors; | ||
3 | |||
4 | use hir::{InFile, Origin}; | ||
5 | use ra_db::FileId; | ||
6 | use ra_ide_db::RootDatabase; | ||
7 | use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken, TextRange}; | ||
8 | |||
9 | use crate::FileRange; | ||
10 | |||
11 | pub(crate) fn original_range(db: &RootDatabase, node: InFile<&SyntaxNode>) -> FileRange { | ||
12 | if let Some((range, Origin::Call)) = original_range_and_origin(db, node) { | ||
13 | return range; | ||
14 | } | ||
15 | |||
16 | if let Some(expansion) = node.file_id.expansion_info(db) { | ||
17 | if let Some(call_node) = expansion.call_node() { | ||
18 | return FileRange { | ||
19 | file_id: call_node.file_id.original_file(db), | ||
20 | range: call_node.value.text_range(), | ||
21 | }; | ||
22 | } | ||
23 | } | ||
24 | |||
25 | FileRange { file_id: node.file_id.original_file(db), range: node.value.text_range() } | ||
26 | } | ||
27 | |||
28 | fn original_range_and_origin( | ||
29 | db: &RootDatabase, | ||
30 | node: InFile<&SyntaxNode>, | ||
31 | ) -> Option<(FileRange, Origin)> { | ||
32 | let expansion = node.file_id.expansion_info(db)?; | ||
33 | |||
34 | // the input node has only one token ? | ||
35 | let single = node.value.first_token()? == node.value.last_token()?; | ||
36 | |||
37 | // FIXME: We should handle recurside macro expansions | ||
38 | let (range, origin) = node.value.descendants().find_map(|it| { | ||
39 | let first = it.first_token()?; | ||
40 | let last = it.last_token()?; | ||
41 | |||
42 | if !single && first == last { | ||
43 | return None; | ||
44 | } | ||
45 | |||
46 | // Try to map first and last tokens of node, and, if success, return the union range of mapped tokens | ||
47 | let (first, first_origin) = expansion.map_token_up(node.with_value(&first))?; | ||
48 | let (last, last_origin) = expansion.map_token_up(node.with_value(&last))?; | ||
49 | |||
50 | if first.file_id != last.file_id || first_origin != last_origin { | ||
51 | return None; | ||
52 | } | ||
53 | |||
54 | // FIXME: Add union method in TextRange | ||
55 | Some(( | ||
56 | first.with_value(union_range(first.value.text_range(), last.value.text_range())), | ||
57 | first_origin, | ||
58 | )) | ||
59 | })?; | ||
60 | |||
61 | return Some(( | ||
62 | FileRange { file_id: range.file_id.original_file(db), range: range.value }, | ||
63 | origin, | ||
64 | )); | ||
65 | |||
66 | fn union_range(a: TextRange, b: TextRange) -> TextRange { | ||
67 | let start = a.start().min(b.start()); | ||
68 | let end = a.end().max(b.end()); | ||
69 | TextRange::from_to(start, end) | ||
70 | } | ||
71 | } | ||
72 | |||
73 | pub(crate) fn descend_into_macros( | ||
74 | db: &RootDatabase, | ||
75 | file_id: FileId, | ||
76 | token: SyntaxToken, | ||
77 | ) -> InFile<SyntaxToken> { | ||
78 | let src = InFile::new(file_id.into(), token); | ||
79 | |||
80 | let source_analyzer = | ||
81 | hir::SourceAnalyzer::new(db, src.with_value(src.value.parent()).as_ref(), None); | ||
82 | |||
83 | descend_into_macros_with_analyzer(db, &source_analyzer, src) | ||
84 | } | ||
85 | |||
86 | pub(crate) fn descend_into_macros_with_analyzer( | ||
87 | db: &RootDatabase, | ||
88 | source_analyzer: &hir::SourceAnalyzer, | ||
89 | src: InFile<SyntaxToken>, | ||
90 | ) -> InFile<SyntaxToken> { | ||
91 | successors(Some(src), |token| { | ||
92 | let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; | ||
93 | let tt = macro_call.token_tree()?; | ||
94 | if !token.value.text_range().is_subrange(&tt.syntax().text_range()) { | ||
95 | return None; | ||
96 | } | ||
97 | let exp = source_analyzer.expand(db, token.with_value(¯o_call))?; | ||
98 | exp.map_token_down(db, token.as_ref()) | ||
99 | }) | ||
100 | .last() | ||
101 | .unwrap() | ||
102 | } | ||