diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-03-09 08:56:58 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-03-09 08:56:58 +0000 |
commit | beb4f4954179998e317db33e47a48a9bb7374977 (patch) | |
tree | e2af54ce707bfcdd0a0cd3fc5d547f43fc9fb7d1 /crates/ra_hir | |
parent | 30062da6284052deac04c759540f81d5b326689c (diff) | |
parent | afdf08e964345ac4a884a5630772611ba81f6969 (diff) |
Merge #3513
3513: Completion in macros r=matklad a=flodiebold
I experimented a bit with completion in macros. It's kind of working, but there are a lot of rough edges.
- I'm trying to expand the macro call with the inserted fake token. This requires some hacky additions on the HIR level to be able to do "hypothetical" expansions. There should probably be a nicer API for this, if we want to do it this way. I'm not sure whether it's worth it, because we still can't do a lot if the original macro call didn't expand in nearly the same way. E.g. if we have something like `println!("", x<|>)` the expansions will look the same and everything is fine; but in that case we could maybe have achieved the same result in a simpler way. If we have something like `m!(<|>)` where `m!()` doesn't even expand or expands to something very different, we don't really know what to do anyway.
- Relatedly, there are a lot of cases where this doesn't work because either the original call or the hypothetical call doesn't expand. E.g. if we have `m!(x.<|>)` the original token tree doesn't parse as an expression; if we have `m!(match x { <|> })` the hypothetical token tree doesn't parse. It would be nice if we could have better error recovery in these cases.
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 35 |
2 files changed, 36 insertions, 1 deletions
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index 0555a0de7..266c4cff3 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml | |||
@@ -12,6 +12,8 @@ log = "0.4.8" | |||
12 | rustc-hash = "1.1.0" | 12 | rustc-hash = "1.1.0" |
13 | either = "1.5.3" | 13 | either = "1.5.3" |
14 | 14 | ||
15 | itertools = "0.8.2" | ||
16 | |||
15 | ra_syntax = { path = "../ra_syntax" } | 17 | ra_syntax = { path = "../ra_syntax" } |
16 | ra_db = { path = "../ra_db" } | 18 | ra_db = { path = "../ra_db" } |
17 | ra_prof = { path = "../ra_prof" } | 19 | ra_prof = { path = "../ra_prof" } |
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 965d185a4..3782a9984 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -6,7 +6,7 @@ use std::{cell::RefCell, fmt, iter::successors}; | |||
6 | 6 | ||
7 | use hir_def::{ | 7 | use hir_def::{ |
8 | resolver::{self, HasResolver, Resolver}, | 8 | resolver::{self, HasResolver, Resolver}, |
9 | TraitId, | 9 | AsMacroCall, TraitId, |
10 | }; | 10 | }; |
11 | use hir_expand::ExpansionInfo; | 11 | use hir_expand::ExpansionInfo; |
12 | use ra_db::{FileId, FileRange}; | 12 | use ra_db::{FileId, FileRange}; |
@@ -70,6 +70,20 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
70 | Some(node) | 70 | Some(node) |
71 | } | 71 | } |
72 | 72 | ||
73 | pub fn expand_hypothetical( | ||
74 | &self, | ||
75 | actual_macro_call: &ast::MacroCall, | ||
76 | hypothetical_args: &ast::TokenTree, | ||
77 | token_to_map: SyntaxToken, | ||
78 | ) -> Option<(SyntaxNode, SyntaxToken)> { | ||
79 | let macro_call = | ||
80 | self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); | ||
81 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); | ||
82 | let macro_call_id = macro_call | ||
83 | .as_call_id(self.db, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; | ||
84 | hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map) | ||
85 | } | ||
86 | |||
73 | pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { | 87 | pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { |
74 | let parent = token.parent(); | 88 | let parent = token.parent(); |
75 | let parent = self.find_file(parent); | 89 | let parent = self.find_file(parent); |
@@ -104,6 +118,25 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
104 | node.ancestors_with_macros(self.db).map(|it| it.value) | 118 | node.ancestors_with_macros(self.db).map(|it| it.value) |
105 | } | 119 | } |
106 | 120 | ||
121 | pub fn ancestors_at_offset_with_macros( | ||
122 | &self, | ||
123 | node: &SyntaxNode, | ||
124 | offset: TextUnit, | ||
125 | ) -> impl Iterator<Item = SyntaxNode> + '_ { | ||
126 | use itertools::Itertools; | ||
127 | node.token_at_offset(offset) | ||
128 | .map(|token| self.ancestors_with_macros(token.parent())) | ||
129 | .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) | ||
130 | } | ||
131 | |||
132 | pub fn find_node_at_offset_with_macros<N: AstNode>( | ||
133 | &self, | ||
134 | node: &SyntaxNode, | ||
135 | offset: TextUnit, | ||
136 | ) -> Option<N> { | ||
137 | self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast) | ||
138 | } | ||
139 | |||
107 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { | 140 | pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { |
108 | self.analyze(expr.syntax()).type_of(self.db, &expr) | 141 | self.analyze(expr.syntax()).type_of(self.db, &expr) |
109 | } | 142 | } |