aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/ast_transform.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-02-26 12:04:22 +0000
committerGitHub <[email protected]>2020-02-26 12:04:22 +0000
commit5c64ad27e041bcdb281c0a751720ceb3a6369d04 (patch)
tree12d89798f61b276f8bd640db07276a7d4e92b1c2 /crates/ra_assists/src/ast_transform.rs
parent04deae3dba7c9b7054f7a1d64e4b93a05aecc132 (diff)
parentc3a4c4429de83450654795534e64e878a774a088 (diff)
Merge pull request #3222 from matklad/identity
Introduce Semantics API
Diffstat (limited to 'crates/ra_assists/src/ast_transform.rs')
-rw-r--r--crates/ra_assists/src/ast_transform.rs65
1 files changed, 30 insertions, 35 deletions
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs
index c6d15af5f..7846e9798 100644
--- a/crates/ra_assists/src/ast_transform.rs
+++ b/crates/ra_assists/src/ast_transform.rs
@@ -1,15 +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::{InFile, PathResolution}; 4use hir::{PathResolution, SemanticsScope};
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::ast::{self, AstNode}; 6use ra_syntax::ast::{self, AstNode};
7 7
8pub trait AstTransform<'a> { 8pub trait AstTransform<'a> {
9 fn get_substitution( 9 fn get_substitution(&self, node: &ra_syntax::SyntaxNode) -> Option<ra_syntax::SyntaxNode>;
10 &self,
11 node: InFile<&ra_syntax::SyntaxNode>,
12 ) -> Option<ra_syntax::SyntaxNode>;
13 10
14 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>;
15 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>
@@ -23,10 +20,7 @@ pub trait AstTransform<'a> {
23struct NullTransformer; 20struct NullTransformer;
24 21
25impl<'a> AstTransform<'a> for NullTransformer { 22impl<'a> AstTransform<'a> for NullTransformer {
26 fn get_substitution( 23 fn get_substitution(&self, _node: &ra_syntax::SyntaxNode) -> Option<ra_syntax::SyntaxNode> {
27 &self,
28 _node: InFile<&ra_syntax::SyntaxNode>,
29 ) -> Option<ra_syntax::SyntaxNode> {
30 None 24 None
31 } 25 }
32 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> {
@@ -35,14 +29,16 @@ impl<'a> AstTransform<'a> for NullTransformer {
35} 29}
36 30
37pub struct SubstituteTypeParams<'a> { 31pub struct SubstituteTypeParams<'a> {
38 db: &'a RootDatabase, 32 source_scope: &'a SemanticsScope<'a, RootDatabase>,
39 substs: FxHashMap<hir::TypeParam, ast::TypeRef>, 33 substs: FxHashMap<hir::TypeParam, ast::TypeRef>,
40 previous: Box<dyn AstTransform<'a> + 'a>, 34 previous: Box<dyn AstTransform<'a> + 'a>,
41} 35}
42 36
43impl<'a> SubstituteTypeParams<'a> { 37impl<'a> SubstituteTypeParams<'a> {
44 pub fn for_trait_impl( 38 pub fn for_trait_impl(
39 source_scope: &'a SemanticsScope<'a, RootDatabase>,
45 db: &'a RootDatabase, 40 db: &'a RootDatabase,
41 // FIXME: there's implicit invariant that `trait_` and `source_scope` match...
46 trait_: hir::Trait, 42 trait_: hir::Trait,
47 impl_block: ast::ImplBlock, 43 impl_block: ast::ImplBlock,
48 ) -> SubstituteTypeParams<'a> { 44 ) -> SubstituteTypeParams<'a> {
@@ -56,7 +52,7 @@ impl<'a> SubstituteTypeParams<'a> {
56 .zip(substs.into_iter()) 52 .zip(substs.into_iter())
57 .collect(); 53 .collect();
58 return SubstituteTypeParams { 54 return SubstituteTypeParams {
59 db, 55 source_scope,
60 substs: substs_by_param, 56 substs: substs_by_param,
61 previous: Box::new(NullTransformer), 57 previous: Box::new(NullTransformer),
62 }; 58 };
@@ -80,15 +76,15 @@ impl<'a> SubstituteTypeParams<'a> {
80 } 76 }
81 fn get_substitution_inner( 77 fn get_substitution_inner(
82 &self, 78 &self,
83 node: InFile<&ra_syntax::SyntaxNode>, 79 node: &ra_syntax::SyntaxNode,
84 ) -> Option<ra_syntax::SyntaxNode> { 80 ) -> Option<ra_syntax::SyntaxNode> {
85 let type_ref = ast::TypeRef::cast(node.value.clone())?; 81 let type_ref = ast::TypeRef::cast(node.clone())?;
86 let path = match &type_ref { 82 let path = match &type_ref {
87 ast::TypeRef::PathType(path_type) => path_type.path()?, 83 ast::TypeRef::PathType(path_type) => path_type.path()?,
88 _ => return None, 84 _ => return None,
89 }; 85 };
90 let analyzer = hir::SourceAnalyzer::new(self.db, node, None); 86 let path = hir::Path::from_ast(path)?;
91 let resolution = analyzer.resolve_path(self.db, &path)?; 87 let resolution = self.source_scope.resolve_hir_path(&path)?;
92 match resolution { 88 match resolution {
93 hir::PathResolution::TypeParam(tp) => Some(self.substs.get(&tp)?.syntax().clone()), 89 hir::PathResolution::TypeParam(tp) => Some(self.substs.get(&tp)?.syntax().clone()),
94 _ => None, 90 _ => None,
@@ -97,10 +93,7 @@ impl<'a> SubstituteTypeParams<'a> {
97} 93}
98 94
99impl<'a> AstTransform<'a> for SubstituteTypeParams<'a> { 95impl<'a> AstTransform<'a> for SubstituteTypeParams<'a> {
100 fn get_substitution( 96 fn get_substitution(&self, node: &ra_syntax::SyntaxNode) -> Option<ra_syntax::SyntaxNode> {
101 &self,
102 node: InFile<&ra_syntax::SyntaxNode>,
103 ) -> Option<ra_syntax::SyntaxNode> {
104 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))
105 } 98 }
106 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> {
@@ -109,29 +102,34 @@ impl<'a> AstTransform<'a> for SubstituteTypeParams<'a> {
109} 102}
110 103
111pub struct QualifyPaths<'a> { 104pub struct QualifyPaths<'a> {
105 target_scope: &'a SemanticsScope<'a, RootDatabase>,
106 source_scope: &'a SemanticsScope<'a, RootDatabase>,
112 db: &'a RootDatabase, 107 db: &'a RootDatabase,
113 from: Option<hir::Module>,
114 previous: Box<dyn AstTransform<'a> + 'a>, 108 previous: Box<dyn AstTransform<'a> + 'a>,
115} 109}
116 110
117impl<'a> QualifyPaths<'a> { 111impl<'a> QualifyPaths<'a> {
118 pub fn new(db: &'a RootDatabase, from: Option<hir::Module>) -> Self { 112 pub fn new(
119 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) }
120 } 118 }
121 119
122 fn get_substitution_inner( 120 fn get_substitution_inner(
123 &self, 121 &self,
124 node: InFile<&ra_syntax::SyntaxNode>, 122 node: &ra_syntax::SyntaxNode,
125 ) -> Option<ra_syntax::SyntaxNode> { 123 ) -> Option<ra_syntax::SyntaxNode> {
126 // FIXME handle value ns? 124 // FIXME handle value ns?
127 let from = self.from?; 125 let from = self.target_scope.module()?;
128 let p = ast::Path::cast(node.value.clone())?; 126 let p = ast::Path::cast(node.clone())?;
129 if p.segment().and_then(|s| s.param_list()).is_some() { 127 if p.segment().and_then(|s| s.param_list()).is_some() {
130 // 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
131 return None; 129 return None;
132 } 130 }
133 let analyzer = hir::SourceAnalyzer::new(self.db, node, None); 131 let hir_path = hir::Path::from_ast(p.clone());
134 let resolution = analyzer.resolve_path(self.db, &p)?; 132 let resolution = self.source_scope.resolve_hir_path(&hir_path?)?;
135 match resolution { 133 match resolution {
136 PathResolution::Def(def) => { 134 PathResolution::Def(def) => {
137 let found_path = from.find_use_path(self.db, def)?; 135 let found_path = from.find_use_path(self.db, def)?;
@@ -140,7 +138,7 @@ impl<'a> QualifyPaths<'a> {
140 let type_args = p 138 let type_args = p
141 .segment() 139 .segment()
142 .and_then(|s| s.type_arg_list()) 140 .and_then(|s| s.type_arg_list())
143 .map(|arg_list| apply(self, node.with_value(arg_list))); 141 .map(|arg_list| apply(self, arg_list));
144 if let Some(type_args) = type_args { 142 if let Some(type_args) = type_args {
145 let last_segment = path.segment().unwrap(); 143 let last_segment = path.segment().unwrap();
146 path = path.with_segment(last_segment.with_type_args(type_args)) 144 path = path.with_segment(last_segment.with_type_args(type_args))
@@ -157,11 +155,11 @@ impl<'a> QualifyPaths<'a> {
157 } 155 }
158} 156}
159 157
160pub 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 {
161 let syntax = node.value.syntax(); 159 let syntax = node.syntax();
162 let result = ra_syntax::algo::replace_descendants(syntax, &|element| match element { 160 let result = ra_syntax::algo::replace_descendants(syntax, &|element| match element {
163 ra_syntax::SyntaxElement::Node(n) => { 161 ra_syntax::SyntaxElement::Node(n) => {
164 let replacement = transformer.get_substitution(node.with_value(&n))?; 162 let replacement = transformer.get_substitution(&n)?;
165 Some(replacement.into()) 163 Some(replacement.into())
166 } 164 }
167 _ => None, 165 _ => None,
@@ -170,10 +168,7 @@ pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: InFile<N>
170} 168}
171 169
172impl<'a> AstTransform<'a> for QualifyPaths<'a> { 170impl<'a> AstTransform<'a> for QualifyPaths<'a> {
173 fn get_substitution( 171 fn get_substitution(&self, node: &ra_syntax::SyntaxNode) -> Option<ra_syntax::SyntaxNode> {
174 &self,
175 node: InFile<&ra_syntax::SyntaxNode>,
176 ) -> Option<ra_syntax::SyntaxNode> {
177 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))
178 } 173 }
179 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> {