aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/ast_transform.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/ast_transform.rs')
-rw-r--r--crates/ra_assists/src/ast_transform.rs84
1 files changed, 40 insertions, 44 deletions
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs
index 56b7588ef..7846e9798 100644
--- a/crates/ra_assists/src/ast_transform.rs
+++ b/crates/ra_assists/src/ast_transform.rs
@@ -1,14 +1,12 @@
1//! `AstTransformer`s are functions that replace nodes in an AST and can be easily combined. 1//! `AstTransformer`s are functions that replace nodes in an AST and can be easily combined.
2use rustc_hash::FxHashMap; 2use rustc_hash::FxHashMap;
3 3
4use hir::{db::HirDatabase, InFile, PathResolution}; 4use hir::{PathResolution, SemanticsScope};
5use ra_ide_db::RootDatabase;
5use ra_syntax::ast::{self, AstNode}; 6use ra_syntax::ast::{self, AstNode};
6 7
7pub trait AstTransform<'a> { 8pub trait AstTransform<'a> {
8 fn get_substitution( 9 fn get_substitution(&self, node: &ra_syntax::SyntaxNode) -> Option<ra_syntax::SyntaxNode>;
9 &self,
10 node: InFile<&ra_syntax::SyntaxNode>,
11 ) -> Option<ra_syntax::SyntaxNode>;
12 10
13 fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a>; 11 fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a>;
14 fn or<T: AstTransform<'a> + 'a>(self, other: T) -> Box<dyn AstTransform<'a> + 'a> 12 fn or<T: AstTransform<'a> + 'a>(self, other: T) -> Box<dyn AstTransform<'a> + 'a>
@@ -22,10 +20,7 @@ pub trait AstTransform<'a> {
22struct NullTransformer; 20struct NullTransformer;
23 21
24impl<'a> AstTransform<'a> for NullTransformer { 22impl<'a> AstTransform<'a> for NullTransformer {
25 fn get_substitution( 23 fn get_substitution(&self, _node: &ra_syntax::SyntaxNode) -> Option<ra_syntax::SyntaxNode> {
26 &self,
27 _node: InFile<&ra_syntax::SyntaxNode>,
28 ) -> Option<ra_syntax::SyntaxNode> {
29 None 24 None
30 } 25 }
31 fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> { 26 fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> {
@@ -33,18 +28,20 @@ impl<'a> AstTransform<'a> for NullTransformer {
33 } 28 }
34} 29}
35 30
36pub struct SubstituteTypeParams<'a, DB: HirDatabase> { 31pub struct SubstituteTypeParams<'a> {
37 db: &'a DB, 32 source_scope: &'a SemanticsScope<'a, RootDatabase>,
38 substs: FxHashMap<hir::TypeParam, ast::TypeRef>, 33 substs: FxHashMap<hir::TypeParam, ast::TypeRef>,
39 previous: Box<dyn AstTransform<'a> + 'a>, 34 previous: Box<dyn AstTransform<'a> + 'a>,
40} 35}
41 36
42impl<'a, DB: HirDatabase> SubstituteTypeParams<'a, DB> { 37impl<'a> SubstituteTypeParams<'a> {
43 pub fn for_trait_impl( 38 pub fn for_trait_impl(
44 db: &'a DB, 39 source_scope: &'a SemanticsScope<'a, RootDatabase>,
40 db: &'a RootDatabase,
41 // FIXME: there's implicit invariant that `trait_` and `source_scope` match...
45 trait_: hir::Trait, 42 trait_: hir::Trait,
46 impl_block: ast::ImplBlock, 43 impl_block: ast::ImplBlock,
47 ) -> SubstituteTypeParams<'a, DB> { 44 ) -> SubstituteTypeParams<'a> {
48 let substs = get_syntactic_substs(impl_block).unwrap_or_default(); 45 let substs = get_syntactic_substs(impl_block).unwrap_or_default();
49 let generic_def: hir::GenericDef = trait_.into(); 46 let generic_def: hir::GenericDef = trait_.into();
50 let substs_by_param: FxHashMap<_, _> = generic_def 47 let substs_by_param: FxHashMap<_, _> = generic_def
@@ -55,7 +52,7 @@ impl<'a, DB: HirDatabase> SubstituteTypeParams<'a, DB> {
55 .zip(substs.into_iter()) 52 .zip(substs.into_iter())
56 .collect(); 53 .collect();
57 return SubstituteTypeParams { 54 return SubstituteTypeParams {
58 db, 55 source_scope,
59 substs: substs_by_param, 56 substs: substs_by_param,
60 previous: Box::new(NullTransformer), 57 previous: Box::new(NullTransformer),
61 }; 58 };
@@ -79,15 +76,15 @@ impl<'a, DB: HirDatabase> SubstituteTypeParams<'a, DB> {
79 } 76 }
80 fn get_substitution_inner( 77 fn get_substitution_inner(
81 &self, 78 &self,
82 node: InFile<&ra_syntax::SyntaxNode>, 79 node: &ra_syntax::SyntaxNode,
83 ) -> Option<ra_syntax::SyntaxNode> { 80 ) -> Option<ra_syntax::SyntaxNode> {
84 let type_ref = ast::TypeRef::cast(node.value.clone())?; 81 let type_ref = ast::TypeRef::cast(node.clone())?;
85 let path = match &type_ref { 82 let path = match &type_ref {
86 ast::TypeRef::PathType(path_type) => path_type.path()?, 83 ast::TypeRef::PathType(path_type) => path_type.path()?,
87 _ => return None, 84 _ => return None,
88 }; 85 };
89 let analyzer = hir::SourceAnalyzer::new(self.db, node, None); 86 let path = hir::Path::from_ast(path)?;
90 let resolution = analyzer.resolve_path(self.db, &path)?; 87 let resolution = self.source_scope.resolve_hir_path(&path)?;
91 match resolution { 88 match resolution {
92 hir::PathResolution::TypeParam(tp) => Some(self.substs.get(&tp)?.syntax().clone()), 89 hir::PathResolution::TypeParam(tp) => Some(self.substs.get(&tp)?.syntax().clone()),
93 _ => None, 90 _ => None,
@@ -95,11 +92,8 @@ impl<'a, DB: HirDatabase> SubstituteTypeParams<'a, DB> {
95 } 92 }
96} 93}
97 94
98impl<'a, DB: HirDatabase> AstTransform<'a> for SubstituteTypeParams<'a, DB> { 95impl<'a> AstTransform<'a> for SubstituteTypeParams<'a> {
99 fn get_substitution( 96 fn get_substitution(&self, node: &ra_syntax::SyntaxNode) -> Option<ra_syntax::SyntaxNode> {
100 &self,
101 node: InFile<&ra_syntax::SyntaxNode>,
102 ) -> Option<ra_syntax::SyntaxNode> {
103 self.get_substitution_inner(node).or_else(|| self.previous.get_substitution(node)) 97 self.get_substitution_inner(node).or_else(|| self.previous.get_substitution(node))
104 } 98 }
105 fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> { 99 fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> {
@@ -107,30 +101,35 @@ impl<'a, DB: HirDatabase> AstTransform<'a> for SubstituteTypeParams<'a, DB> {
107 } 101 }
108} 102}
109 103
110pub struct QualifyPaths<'a, DB: HirDatabase> { 104pub struct QualifyPaths<'a> {
111 db: &'a DB, 105 target_scope: &'a SemanticsScope<'a, RootDatabase>,
112 from: Option<hir::Module>, 106 source_scope: &'a SemanticsScope<'a, RootDatabase>,
107 db: &'a RootDatabase,
113 previous: Box<dyn AstTransform<'a> + 'a>, 108 previous: Box<dyn AstTransform<'a> + 'a>,
114} 109}
115 110
116impl<'a, DB: HirDatabase> QualifyPaths<'a, DB> { 111impl<'a> QualifyPaths<'a> {
117 pub fn new(db: &'a DB, from: Option<hir::Module>) -> Self { 112 pub fn new(
118 Self { db, from, previous: Box::new(NullTransformer) } 113 target_scope: &'a SemanticsScope<'a, RootDatabase>,
114 source_scope: &'a SemanticsScope<'a, RootDatabase>,
115 db: &'a RootDatabase,
116 ) -> Self {
117 Self { target_scope, source_scope, db, previous: Box::new(NullTransformer) }
119 } 118 }
120 119
121 fn get_substitution_inner( 120 fn get_substitution_inner(
122 &self, 121 &self,
123 node: InFile<&ra_syntax::SyntaxNode>, 122 node: &ra_syntax::SyntaxNode,
124 ) -> Option<ra_syntax::SyntaxNode> { 123 ) -> Option<ra_syntax::SyntaxNode> {
125 // FIXME handle value ns? 124 // FIXME handle value ns?
126 let from = self.from?; 125 let from = self.target_scope.module()?;
127 let p = ast::Path::cast(node.value.clone())?; 126 let p = ast::Path::cast(node.clone())?;
128 if p.segment().and_then(|s| s.param_list()).is_some() { 127 if p.segment().and_then(|s| s.param_list()).is_some() {
129 // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway 128 // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway
130 return None; 129 return None;
131 } 130 }
132 let analyzer = hir::SourceAnalyzer::new(self.db, node, None); 131 let hir_path = hir::Path::from_ast(p.clone());
133 let resolution = analyzer.resolve_path(self.db, &p)?; 132 let resolution = self.source_scope.resolve_hir_path(&hir_path?)?;
134 match resolution { 133 match resolution {
135 PathResolution::Def(def) => { 134 PathResolution::Def(def) => {
136 let found_path = from.find_use_path(self.db, def)?; 135 let found_path = from.find_use_path(self.db, def)?;
@@ -139,7 +138,7 @@ impl<'a, DB: HirDatabase> QualifyPaths<'a, DB> {
139 let type_args = p 138 let type_args = p
140 .segment() 139 .segment()
141 .and_then(|s| s.type_arg_list()) 140 .and_then(|s| s.type_arg_list())
142 .map(|arg_list| apply(self, node.with_value(arg_list))); 141 .map(|arg_list| apply(self, arg_list));
143 if let Some(type_args) = type_args { 142 if let Some(type_args) = type_args {
144 let last_segment = path.segment().unwrap(); 143 let last_segment = path.segment().unwrap();
145 path = path.with_segment(last_segment.with_type_args(type_args)) 144 path = path.with_segment(last_segment.with_type_args(type_args))
@@ -156,11 +155,11 @@ impl<'a, DB: HirDatabase> QualifyPaths<'a, DB> {
156 } 155 }
157} 156}
158 157
159pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: InFile<N>) -> N { 158pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: N) -> N {
160 let syntax = node.value.syntax(); 159 let syntax = node.syntax();
161 let result = ra_syntax::algo::replace_descendants(syntax, &|element| match element { 160 let result = ra_syntax::algo::replace_descendants(syntax, &|element| match element {
162 ra_syntax::SyntaxElement::Node(n) => { 161 ra_syntax::SyntaxElement::Node(n) => {
163 let replacement = transformer.get_substitution(node.with_value(&n))?; 162 let replacement = transformer.get_substitution(&n)?;
164 Some(replacement.into()) 163 Some(replacement.into())
165 } 164 }
166 _ => None, 165 _ => None,
@@ -168,11 +167,8 @@ pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: InFile<N>
168 N::cast(result).unwrap() 167 N::cast(result).unwrap()
169} 168}
170 169
171impl<'a, DB: HirDatabase> AstTransform<'a> for QualifyPaths<'a, DB> { 170impl<'a> AstTransform<'a> for QualifyPaths<'a> {
172 fn get_substitution( 171 fn get_substitution(&self, node: &ra_syntax::SyntaxNode) -> Option<ra_syntax::SyntaxNode> {
173 &self,
174 node: InFile<&ra_syntax::SyntaxNode>,
175 ) -> Option<ra_syntax::SyntaxNode> {
176 self.get_substitution_inner(node).or_else(|| self.previous.get_substitution(node)) 172 self.get_substitution_inner(node).or_else(|| self.previous.get_substitution(node))
177 } 173 }
178 fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> { 174 fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> {