aboutsummaryrefslogtreecommitdiff
path: root/crates/assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists')
-rw-r--r--crates/assists/src/ast_transform.rs74
1 files changed, 34 insertions, 40 deletions
diff --git a/crates/assists/src/ast_transform.rs b/crates/assists/src/ast_transform.rs
index 835da3bb2..4307e0191 100644
--- a/crates/assists/src/ast_transform.rs
+++ b/crates/assists/src/ast_transform.rs
@@ -5,12 +5,13 @@ use hir::{HirDisplay, PathResolution, SemanticsScope};
5use syntax::{ 5use syntax::{
6 algo::SyntaxRewriter, 6 algo::SyntaxRewriter,
7 ast::{self, AstNode}, 7 ast::{self, AstNode},
8 SyntaxNode,
8}; 9};
9 10
10pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: N) -> N { 11pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: N) -> N {
11 SyntaxRewriter::from_fn(|element| match element { 12 SyntaxRewriter::from_fn(|element| match element {
12 syntax::SyntaxElement::Node(n) => { 13 syntax::SyntaxElement::Node(n) => {
13 let replacement = transformer.get_substitution(&n)?; 14 let replacement = transformer.get_substitution(&n, transformer)?;
14 Some(replacement.into()) 15 Some(replacement.into())
15 } 16 }
16 _ => None, 17 _ => None,
@@ -47,32 +48,35 @@ pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: N) -> N {
47/// We'd want to somehow express this concept simpler, but so far nobody got to 48/// We'd want to somehow express this concept simpler, but so far nobody got to
48/// simplifying this! 49/// simplifying this!
49pub trait AstTransform<'a> { 50pub trait AstTransform<'a> {
50 fn get_substitution(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode>; 51 fn get_substitution(
52 &self,
53 node: &SyntaxNode,
54 recur: &dyn AstTransform<'a>,
55 ) -> Option<SyntaxNode>;
51 56
52 fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a>;
53 fn or<T: AstTransform<'a> + 'a>(self, other: T) -> Box<dyn AstTransform<'a> + 'a> 57 fn or<T: AstTransform<'a> + 'a>(self, other: T) -> Box<dyn AstTransform<'a> + 'a>
54 where 58 where
55 Self: Sized + 'a, 59 Self: Sized + 'a,
56 { 60 {
57 self.chain_before(Box::new(other)) 61 Box::new(Or(Box::new(self), Box::new(other)))
58 } 62 }
59} 63}
60 64
61struct NullTransformer; 65struct Or<'a>(Box<dyn AstTransform<'a> + 'a>, Box<dyn AstTransform<'a> + 'a>);
62 66
63impl<'a> AstTransform<'a> for NullTransformer { 67impl<'a> AstTransform<'a> for Or<'a> {
64 fn get_substitution(&self, _node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> { 68 fn get_substitution(
65 None 69 &self,
66 } 70 node: &SyntaxNode,
67 fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> { 71 recur: &dyn AstTransform<'a>,
68 other 72 ) -> Option<SyntaxNode> {
73 self.0.get_substitution(node, recur).or_else(|| self.1.get_substitution(node, recur))
69 } 74 }
70} 75}
71 76
72pub struct SubstituteTypeParams<'a> { 77pub struct SubstituteTypeParams<'a> {
73 source_scope: &'a SemanticsScope<'a>, 78 source_scope: &'a SemanticsScope<'a>,
74 substs: FxHashMap<hir::TypeParam, ast::Type>, 79 substs: FxHashMap<hir::TypeParam, ast::Type>,
75 previous: Box<dyn AstTransform<'a> + 'a>,
76} 80}
77 81
78impl<'a> SubstituteTypeParams<'a> { 82impl<'a> SubstituteTypeParams<'a> {
@@ -111,11 +115,7 @@ impl<'a> SubstituteTypeParams<'a> {
111 } 115 }
112 }) 116 })
113 .collect(); 117 .collect();
114 return SubstituteTypeParams { 118 return SubstituteTypeParams { source_scope, substs: substs_by_param };
115 source_scope,
116 substs: substs_by_param,
117 previous: Box::new(NullTransformer),
118 };
119 119
120 // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the 120 // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the
121 // trait ref, and then go from the types in the substs back to the syntax). 121 // trait ref, and then go from the types in the substs back to the syntax).
@@ -140,7 +140,14 @@ impl<'a> SubstituteTypeParams<'a> {
140 Some(result) 140 Some(result)
141 } 141 }
142 } 142 }
143 fn get_substitution_inner(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> { 143}
144
145impl<'a> AstTransform<'a> for SubstituteTypeParams<'a> {
146 fn get_substitution(
147 &self,
148 node: &SyntaxNode,
149 _recur: &dyn AstTransform<'a>,
150 ) -> Option<SyntaxNode> {
144 let type_ref = ast::Type::cast(node.clone())?; 151 let type_ref = ast::Type::cast(node.clone())?;
145 let path = match &type_ref { 152 let path = match &type_ref {
146 ast::Type::PathType(path_type) => path_type.path()?, 153 ast::Type::PathType(path_type) => path_type.path()?,
@@ -154,27 +161,23 @@ impl<'a> SubstituteTypeParams<'a> {
154 } 161 }
155} 162}
156 163
157impl<'a> AstTransform<'a> for SubstituteTypeParams<'a> {
158 fn get_substitution(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> {
159 self.get_substitution_inner(node).or_else(|| self.previous.get_substitution(node))
160 }
161 fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> {
162 Box::new(SubstituteTypeParams { previous: other, ..self })
163 }
164}
165
166pub struct QualifyPaths<'a> { 164pub struct QualifyPaths<'a> {
167 target_scope: &'a SemanticsScope<'a>, 165 target_scope: &'a SemanticsScope<'a>,
168 source_scope: &'a SemanticsScope<'a>, 166 source_scope: &'a SemanticsScope<'a>,
169 previous: Box<dyn AstTransform<'a> + 'a>,
170} 167}
171 168
172impl<'a> QualifyPaths<'a> { 169impl<'a> QualifyPaths<'a> {
173 pub fn new(target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>) -> Self { 170 pub fn new(target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>) -> Self {
174 Self { target_scope, source_scope, previous: Box::new(NullTransformer) } 171 Self { target_scope, source_scope }
175 } 172 }
173}
176 174
177 fn get_substitution_inner(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> { 175impl<'a> AstTransform<'a> for QualifyPaths<'a> {
176 fn get_substitution(
177 &self,
178 node: &SyntaxNode,
179 recur: &dyn AstTransform<'a>,
180 ) -> Option<SyntaxNode> {
178 // FIXME handle value ns? 181 // FIXME handle value ns?
179 let from = self.target_scope.module()?; 182 let from = self.target_scope.module()?;
180 let p = ast::Path::cast(node.clone())?; 183 let p = ast::Path::cast(node.clone())?;
@@ -191,7 +194,7 @@ impl<'a> QualifyPaths<'a> {
191 let type_args = p 194 let type_args = p
192 .segment() 195 .segment()
193 .and_then(|s| s.generic_arg_list()) 196 .and_then(|s| s.generic_arg_list())
194 .map(|arg_list| apply(self, arg_list)); 197 .map(|arg_list| apply(recur, arg_list));
195 if let Some(type_args) = type_args { 198 if let Some(type_args) = type_args {
196 let last_segment = path.segment().unwrap(); 199 let last_segment = path.segment().unwrap();
197 path = path.with_segment(last_segment.with_generic_args(type_args)) 200 path = path.with_segment(last_segment.with_generic_args(type_args))
@@ -208,15 +211,6 @@ impl<'a> QualifyPaths<'a> {
208 } 211 }
209} 212}
210 213
211impl<'a> AstTransform<'a> for QualifyPaths<'a> {
212 fn get_substitution(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> {
213 self.get_substitution_inner(node).or_else(|| self.previous.get_substitution(node))
214 }
215 fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> {
216 Box::new(QualifyPaths { previous: other, ..self })
217 }
218}
219
220pub(crate) fn path_to_ast(path: hir::ModPath) -> ast::Path { 214pub(crate) fn path_to_ast(path: hir::ModPath) -> ast::Path {
221 let parse = ast::SourceFile::parse(&path.to_string()); 215 let parse = ast::SourceFile::parse(&path.to_string());
222 parse 216 parse