diff options
author | Ekaterina Babshukova <[email protected]> | 2019-10-05 15:03:03 +0100 |
---|---|---|
committer | Ekaterina Babshukova <[email protected]> | 2019-10-05 15:03:03 +0100 |
commit | 2fc22901730f35405d2bdfe33f88d7b3c6b14304 (patch) | |
tree | c3565f17b7db1625d3c8311432d0bed258b58ca5 | |
parent | dbf869b4d2dac09df17609edf6e67c1611b71dc5 (diff) |
replace AST visitors with macro
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_fn_param.rs | 16 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_keyword.rs | 18 | ||||
-rw-r--r-- | crates/ra_ide_api/src/display/navigation_target.rs | 59 | ||||
-rw-r--r-- | crates/ra_ide_api/src/display/structure.rs | 116 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 185 | ||||
-rw-r--r-- | crates/ra_ide_api/src/hover.rs | 77 | ||||
-rw-r--r-- | crates/ra_ide_api/src/inlay_hints.rs | 104 | ||||
-rw-r--r-- | crates/ra_ide_api/src/symbol_index.rs | 26 | ||||
-rw-r--r-- | crates/ra_syntax/src/lib.rs | 12 | ||||
-rw-r--r-- | crates/ra_syntax/src/validation.rs | 18 |
10 files changed, 334 insertions, 297 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_fn_param.rs b/crates/ra_ide_api/src/completion/complete_fn_param.rs index 844a63f6c..3e936e3ec 100644 --- a/crates/ra_ide_api/src/completion/complete_fn_param.rs +++ b/crates/ra_ide_api/src/completion/complete_fn_param.rs | |||
@@ -1,9 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ast, match_ast, AstNode}; |
4 | algo::visit::{visitor_ctx, VisitorCtx}, | ||
5 | ast, AstNode, | ||
6 | }; | ||
7 | use rustc_hash::FxHashMap; | 4 | use rustc_hash::FxHashMap; |
8 | 5 | ||
9 | use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions}; | 6 | use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions}; |
@@ -19,10 +16,13 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) | |||
19 | 16 | ||
20 | let mut params = FxHashMap::default(); | 17 | let mut params = FxHashMap::default(); |
21 | for node in ctx.token.parent().ancestors() { | 18 | for node in ctx.token.parent().ancestors() { |
22 | let _ = visitor_ctx(&mut params) | 19 | match_ast! { |
23 | .visit::<ast::SourceFile, _>(process) | 20 | match node { |
24 | .visit::<ast::ItemList, _>(process) | 21 | ast::SourceFile(it) => { process(it, &mut params) }, |
25 | .accept(&node); | 22 | ast::ItemList(it) => { process(it, &mut params) }, |
23 | _ => (), | ||
24 | } | ||
25 | } | ||
26 | } | 26 | } |
27 | params | 27 | params |
28 | .into_iter() | 28 | .into_iter() |
diff --git a/crates/ra_ide_api/src/completion/complete_keyword.rs b/crates/ra_ide_api/src/completion/complete_keyword.rs index 3f121d45c..48c688a08 100644 --- a/crates/ra_ide_api/src/completion/complete_keyword.rs +++ b/crates/ra_ide_api/src/completion/complete_keyword.rs | |||
@@ -1,9 +1,8 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | algo::visit::{visitor, Visitor}, | ||
5 | ast::{self, LoopBodyOwner}, | 4 | ast::{self, LoopBodyOwner}, |
6 | AstNode, | 5 | match_ast, AstNode, |
7 | SyntaxKind::*, | 6 | SyntaxKind::*, |
8 | SyntaxToken, | 7 | SyntaxToken, |
9 | }; | 8 | }; |
@@ -84,12 +83,15 @@ fn is_in_loop_body(leaf: &SyntaxToken) -> bool { | |||
84 | if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { | 83 | if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { |
85 | break; | 84 | break; |
86 | } | 85 | } |
87 | let loop_body = visitor() | 86 | let loop_body = match_ast! { |
88 | .visit::<ast::ForExpr, _>(|it| it.loop_body()) | 87 | match node { |
89 | .visit::<ast::WhileExpr, _>(|it| it.loop_body()) | 88 | ast::ForExpr(it) => { it.loop_body() }, |
90 | .visit::<ast::LoopExpr, _>(|it| it.loop_body()) | 89 | ast::WhileExpr(it) => { it.loop_body() }, |
91 | .accept(&node); | 90 | ast::LoopExpr(it) => { it.loop_body() }, |
92 | if let Some(Some(body)) = loop_body { | 91 | _ => None, |
92 | } | ||
93 | }; | ||
94 | if let Some(body) = loop_body { | ||
93 | if leaf.text_range().is_subrange(&body.syntax().text_range()) { | 95 | if leaf.text_range().is_subrange(&body.syntax().text_range()) { |
94 | return true; | 96 | return true; |
95 | } | 97 | } |
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs index 60ae802c0..d0b1a8a2a 100644 --- a/crates/ra_ide_api/src/display/navigation_target.rs +++ b/crates/ra_ide_api/src/display/navigation_target.rs | |||
@@ -3,9 +3,8 @@ | |||
3 | use hir::{AssocItem, FieldSource, HasSource, ModuleSource}; | 3 | use hir::{AssocItem, FieldSource, HasSource, ModuleSource}; |
4 | use ra_db::{FileId, SourceDatabase}; | 4 | use ra_db::{FileId, SourceDatabase}; |
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | algo::visit::{visitor, Visitor}, | ||
7 | ast::{self, DocCommentsOwner}, | 6 | ast::{self, DocCommentsOwner}, |
8 | AstNode, AstPtr, SmolStr, | 7 | match_ast, AstNode, AstPtr, SmolStr, |
9 | SyntaxKind::{self, NAME}, | 8 | SyntaxKind::{self, NAME}, |
10 | SyntaxNode, TextRange, | 9 | SyntaxNode, TextRange, |
11 | }; | 10 | }; |
@@ -308,19 +307,22 @@ pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option | |||
308 | let parse = db.parse(symbol.file_id); | 307 | let parse = db.parse(symbol.file_id); |
309 | let node = symbol.ptr.to_node(parse.tree().syntax()); | 308 | let node = symbol.ptr.to_node(parse.tree().syntax()); |
310 | 309 | ||
311 | visitor() | 310 | match_ast! { |
312 | .visit(|it: ast::FnDef| it.doc_comment_text()) | 311 | match node { |
313 | .visit(|it: ast::StructDef| it.doc_comment_text()) | 312 | ast::FnDef(it) => { it.doc_comment_text() }, |
314 | .visit(|it: ast::EnumDef| it.doc_comment_text()) | 313 | ast::StructDef(it) => { it.doc_comment_text() }, |
315 | .visit(|it: ast::TraitDef| it.doc_comment_text()) | 314 | ast::EnumDef(it) => { it.doc_comment_text() }, |
316 | .visit(|it: ast::Module| it.doc_comment_text()) | 315 | ast::TraitDef(it) => { it.doc_comment_text() }, |
317 | .visit(|it: ast::TypeAliasDef| it.doc_comment_text()) | 316 | ast::Module(it) => { it.doc_comment_text() }, |
318 | .visit(|it: ast::ConstDef| it.doc_comment_text()) | 317 | ast::TypeAliasDef(it) => { it.doc_comment_text() }, |
319 | .visit(|it: ast::StaticDef| it.doc_comment_text()) | 318 | ast::ConstDef(it) => { it.doc_comment_text() }, |
320 | .visit(|it: ast::RecordFieldDef| it.doc_comment_text()) | 319 | ast::StaticDef(it) => { it.doc_comment_text() }, |
321 | .visit(|it: ast::EnumVariant| it.doc_comment_text()) | 320 | ast::RecordFieldDef(it) => { it.doc_comment_text() }, |
322 | .visit(|it: ast::MacroCall| it.doc_comment_text()) | 321 | ast::EnumVariant(it) => { it.doc_comment_text() }, |
323 | .accept(&node)? | 322 | ast::MacroCall(it) => { it.doc_comment_text() }, |
323 | _ => None, | ||
324 | } | ||
325 | } | ||
324 | } | 326 | } |
325 | 327 | ||
326 | /// Get a description of a symbol. | 328 | /// Get a description of a symbol. |
@@ -330,16 +332,19 @@ pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> | |||
330 | let parse = db.parse(symbol.file_id); | 332 | let parse = db.parse(symbol.file_id); |
331 | let node = symbol.ptr.to_node(parse.tree().syntax()); | 333 | let node = symbol.ptr.to_node(parse.tree().syntax()); |
332 | 334 | ||
333 | visitor() | 335 | match_ast! { |
334 | .visit(|node: ast::FnDef| node.short_label()) | 336 | match node { |
335 | .visit(|node: ast::StructDef| node.short_label()) | 337 | ast::FnDef(it) => { it.short_label() }, |
336 | .visit(|node: ast::EnumDef| node.short_label()) | 338 | ast::StructDef(it) => { it.short_label() }, |
337 | .visit(|node: ast::TraitDef| node.short_label()) | 339 | ast::EnumDef(it) => { it.short_label() }, |
338 | .visit(|node: ast::Module| node.short_label()) | 340 | ast::TraitDef(it) => { it.short_label() }, |
339 | .visit(|node: ast::TypeAliasDef| node.short_label()) | 341 | ast::Module(it) => { it.short_label() }, |
340 | .visit(|node: ast::ConstDef| node.short_label()) | 342 | ast::TypeAliasDef(it) => { it.short_label() }, |
341 | .visit(|node: ast::StaticDef| node.short_label()) | 343 | ast::ConstDef(it) => { it.short_label() }, |
342 | .visit(|node: ast::RecordFieldDef| node.short_label()) | 344 | ast::StaticDef(it) => { it.short_label() }, |
343 | .visit(|node: ast::EnumVariant| node.short_label()) | 345 | ast::RecordFieldDef(it) => { it.short_label() }, |
344 | .accept(&node)? | 346 | ast::EnumVariant(it) => { it.short_label() }, |
347 | _ => None, | ||
348 | } | ||
349 | } | ||
345 | } | 350 | } |
diff --git a/crates/ra_ide_api/src/display/structure.rs b/crates/ra_ide_api/src/display/structure.rs index 8815df747..ddd8b7b20 100644 --- a/crates/ra_ide_api/src/display/structure.rs +++ b/crates/ra_ide_api/src/display/structure.rs | |||
@@ -3,9 +3,8 @@ | |||
3 | use crate::TextRange; | 3 | use crate::TextRange; |
4 | 4 | ||
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | algo::visit::{visitor, Visitor}, | ||
7 | ast::{self, AttrsOwner, NameOwner, TypeAscriptionOwner, TypeParamsOwner}, | 6 | ast::{self, AttrsOwner, NameOwner, TypeAscriptionOwner, TypeParamsOwner}, |
8 | AstNode, SourceFile, SyntaxKind, SyntaxNode, WalkEvent, | 7 | match_ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, WalkEvent, |
9 | }; | 8 | }; |
10 | 9 | ||
11 | #[derive(Debug, Clone)] | 10 | #[derive(Debug, Clone)] |
@@ -101,63 +100,66 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> { | |||
101 | }) | 100 | }) |
102 | } | 101 | } |
103 | 102 | ||
104 | visitor() | 103 | match_ast! { |
105 | .visit(|fn_def: ast::FnDef| { | 104 | match node { |
106 | let mut detail = String::from("fn"); | 105 | ast::FnDef(it) => { |
107 | if let Some(type_param_list) = fn_def.type_param_list() { | 106 | let mut detail = String::from("fn"); |
108 | collapse_ws(type_param_list.syntax(), &mut detail); | 107 | if let Some(type_param_list) = it.type_param_list() { |
109 | } | 108 | collapse_ws(type_param_list.syntax(), &mut detail); |
110 | if let Some(param_list) = fn_def.param_list() { | 109 | } |
111 | collapse_ws(param_list.syntax(), &mut detail); | 110 | if let Some(param_list) = it.param_list() { |
112 | } | 111 | collapse_ws(param_list.syntax(), &mut detail); |
113 | if let Some(ret_type) = fn_def.ret_type() { | 112 | } |
114 | detail.push_str(" "); | 113 | if let Some(ret_type) = it.ret_type() { |
115 | collapse_ws(ret_type.syntax(), &mut detail); | 114 | detail.push_str(" "); |
116 | } | 115 | collapse_ws(ret_type.syntax(), &mut detail); |
117 | |||
118 | decl_with_detail(fn_def, Some(detail)) | ||
119 | }) | ||
120 | .visit(decl::<ast::StructDef>) | ||
121 | .visit(decl::<ast::EnumDef>) | ||
122 | .visit(decl::<ast::EnumVariant>) | ||
123 | .visit(decl::<ast::TraitDef>) | ||
124 | .visit(decl::<ast::Module>) | ||
125 | .visit(|td: ast::TypeAliasDef| { | ||
126 | let ty = td.type_ref(); | ||
127 | decl_with_type_ref(td, ty) | ||
128 | }) | ||
129 | .visit(decl_with_ascription::<ast::RecordFieldDef>) | ||
130 | .visit(decl_with_ascription::<ast::ConstDef>) | ||
131 | .visit(decl_with_ascription::<ast::StaticDef>) | ||
132 | .visit(|im: ast::ImplBlock| { | ||
133 | let target_type = im.target_type()?; | ||
134 | let target_trait = im.target_trait(); | ||
135 | let label = match target_trait { | ||
136 | None => format!("impl {}", target_type.syntax().text()), | ||
137 | Some(t) => { | ||
138 | format!("impl {} for {}", t.syntax().text(), target_type.syntax().text(),) | ||
139 | } | 116 | } |
140 | }; | ||
141 | 117 | ||
142 | let node = StructureNode { | 118 | decl_with_detail(it, Some(detail)) |
143 | parent: None, | 119 | }, |
144 | label, | 120 | ast::StructDef(it) => { decl(it) }, |
145 | navigation_range: target_type.syntax().text_range(), | 121 | ast::EnumDef(it) => { decl(it) }, |
146 | node_range: im.syntax().text_range(), | 122 | ast::EnumVariant(it) => { decl(it) }, |
147 | kind: im.syntax().kind(), | 123 | ast::TraitDef(it) => { decl(it) }, |
148 | detail: None, | 124 | ast::Module(it) => { decl(it) }, |
149 | deprecated: false, | 125 | ast::TypeAliasDef(it) => { |
150 | }; | 126 | let ty = it.type_ref(); |
151 | Some(node) | 127 | decl_with_type_ref(it, ty) |
152 | }) | 128 | }, |
153 | .visit(|mc: ast::MacroCall| { | 129 | ast::RecordFieldDef(it) => { decl_with_ascription(it) }, |
154 | let first_token = mc.syntax().first_token().unwrap(); | 130 | ast::ConstDef(it) => { decl_with_ascription(it) }, |
155 | if first_token.text().as_str() != "macro_rules" { | 131 | ast::StaticDef(it) => { decl_with_ascription(it) }, |
156 | return None; | 132 | ast::ImplBlock(it) => { |
157 | } | 133 | let target_type = it.target_type()?; |
158 | decl(mc) | 134 | let target_trait = it.target_trait(); |
159 | }) | 135 | let label = match target_trait { |
160 | .accept(&node)? | 136 | None => format!("impl {}", target_type.syntax().text()), |
137 | Some(t) => { | ||
138 | format!("impl {} for {}", t.syntax().text(), target_type.syntax().text(),) | ||
139 | } | ||
140 | }; | ||
141 | |||
142 | let node = StructureNode { | ||
143 | parent: None, | ||
144 | label, | ||
145 | navigation_range: target_type.syntax().text_range(), | ||
146 | node_range: it.syntax().text_range(), | ||
147 | kind: it.syntax().kind(), | ||
148 | detail: None, | ||
149 | deprecated: false, | ||
150 | }; | ||
151 | Some(node) | ||
152 | }, | ||
153 | ast::MacroCall(it) => { | ||
154 | let first_token = it.syntax().first_token().unwrap(); | ||
155 | if first_token.text().as_str() != "macro_rules" { | ||
156 | return None; | ||
157 | } | ||
158 | decl(it) | ||
159 | }, | ||
160 | _ => None, | ||
161 | } | ||
162 | } | ||
161 | } | 163 | } |
162 | 164 | ||
163 | #[cfg(test)] | 165 | #[cfg(test)] |
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 567d4a674..41a88314f 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs | |||
@@ -2,12 +2,9 @@ | |||
2 | 2 | ||
3 | use ra_db::{FileId, SourceDatabase}; | 3 | use ra_db::{FileId, SourceDatabase}; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | algo::{ | 5 | algo::find_node_at_offset, |
6 | find_node_at_offset, | ||
7 | visit::{visitor, Visitor}, | ||
8 | }, | ||
9 | ast::{self, DocCommentsOwner}, | 6 | ast::{self, DocCommentsOwner}, |
10 | AstNode, SyntaxNode, | 7 | match_ast, AstNode, SyntaxNode, |
11 | }; | 8 | }; |
12 | 9 | ||
13 | use crate::{ | 10 | use crate::{ |
@@ -114,91 +111,99 @@ pub(crate) fn name_definition( | |||
114 | } | 111 | } |
115 | 112 | ||
116 | fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> { | 113 | fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> { |
117 | visitor() | 114 | match_ast! { |
118 | .visit(|node: ast::StructDef| { | 115 | match node { |
119 | NavigationTarget::from_named( | 116 | ast::StructDef(it) => { |
120 | file_id, | 117 | Some(NavigationTarget::from_named( |
121 | &node, | 118 | file_id, |
122 | node.doc_comment_text(), | 119 | &it, |
123 | node.short_label(), | 120 | it.doc_comment_text(), |
124 | ) | 121 | it.short_label(), |
125 | }) | 122 | )) |
126 | .visit(|node: ast::EnumDef| { | 123 | }, |
127 | NavigationTarget::from_named( | 124 | ast::EnumDef(it) => { |
128 | file_id, | 125 | Some(NavigationTarget::from_named( |
129 | &node, | 126 | file_id, |
130 | node.doc_comment_text(), | 127 | &it, |
131 | node.short_label(), | 128 | it.doc_comment_text(), |
132 | ) | 129 | it.short_label(), |
133 | }) | 130 | )) |
134 | .visit(|node: ast::EnumVariant| { | 131 | }, |
135 | NavigationTarget::from_named( | 132 | ast::EnumVariant(it) => { |
136 | file_id, | 133 | Some(NavigationTarget::from_named( |
137 | &node, | 134 | file_id, |
138 | node.doc_comment_text(), | 135 | &it, |
139 | node.short_label(), | 136 | it.doc_comment_text(), |
140 | ) | 137 | it.short_label(), |
141 | }) | 138 | )) |
142 | .visit(|node: ast::FnDef| { | 139 | }, |
143 | NavigationTarget::from_named( | 140 | ast::FnDef(it) => { |
144 | file_id, | 141 | Some(NavigationTarget::from_named( |
145 | &node, | 142 | file_id, |
146 | node.doc_comment_text(), | 143 | &it, |
147 | node.short_label(), | 144 | it.doc_comment_text(), |
148 | ) | 145 | it.short_label(), |
149 | }) | 146 | )) |
150 | .visit(|node: ast::TypeAliasDef| { | 147 | }, |
151 | NavigationTarget::from_named( | 148 | ast::TypeAliasDef(it) => { |
152 | file_id, | 149 | Some(NavigationTarget::from_named( |
153 | &node, | 150 | file_id, |
154 | node.doc_comment_text(), | 151 | &it, |
155 | node.short_label(), | 152 | it.doc_comment_text(), |
156 | ) | 153 | it.short_label(), |
157 | }) | 154 | )) |
158 | .visit(|node: ast::ConstDef| { | 155 | }, |
159 | NavigationTarget::from_named( | 156 | ast::ConstDef(it) => { |
160 | file_id, | 157 | Some(NavigationTarget::from_named( |
161 | &node, | 158 | file_id, |
162 | node.doc_comment_text(), | 159 | &it, |
163 | node.short_label(), | 160 | it.doc_comment_text(), |
164 | ) | 161 | it.short_label(), |
165 | }) | 162 | )) |
166 | .visit(|node: ast::StaticDef| { | 163 | }, |
167 | NavigationTarget::from_named( | 164 | ast::StaticDef(it) => { |
168 | file_id, | 165 | Some(NavigationTarget::from_named( |
169 | &node, | 166 | file_id, |
170 | node.doc_comment_text(), | 167 | &it, |
171 | node.short_label(), | 168 | it.doc_comment_text(), |
172 | ) | 169 | it.short_label(), |
173 | }) | 170 | )) |
174 | .visit(|node: ast::TraitDef| { | 171 | }, |
175 | NavigationTarget::from_named( | 172 | ast::TraitDef(it) => { |
176 | file_id, | 173 | Some(NavigationTarget::from_named( |
177 | &node, | 174 | file_id, |
178 | node.doc_comment_text(), | 175 | &it, |
179 | node.short_label(), | 176 | it.doc_comment_text(), |
180 | ) | 177 | it.short_label(), |
181 | }) | 178 | )) |
182 | .visit(|node: ast::RecordFieldDef| { | 179 | }, |
183 | NavigationTarget::from_named( | 180 | ast::RecordFieldDef(it) => { |
184 | file_id, | 181 | Some(NavigationTarget::from_named( |
185 | &node, | 182 | file_id, |
186 | node.doc_comment_text(), | 183 | &it, |
187 | node.short_label(), | 184 | it.doc_comment_text(), |
188 | ) | 185 | it.short_label(), |
189 | }) | 186 | )) |
190 | .visit(|node: ast::Module| { | 187 | }, |
191 | NavigationTarget::from_named( | 188 | ast::Module(it) => { |
192 | file_id, | 189 | Some(NavigationTarget::from_named( |
193 | &node, | 190 | file_id, |
194 | node.doc_comment_text(), | 191 | &it, |
195 | node.short_label(), | 192 | it.doc_comment_text(), |
196 | ) | 193 | it.short_label(), |
197 | }) | 194 | )) |
198 | .visit(|node: ast::MacroCall| { | 195 | }, |
199 | NavigationTarget::from_named(file_id, &node, node.doc_comment_text(), None) | 196 | ast::MacroCall(it) => { |
200 | }) | 197 | Some(NavigationTarget::from_named( |
201 | .accept(node) | 198 | file_id, |
199 | &it, | ||
200 | it.doc_comment_text(), | ||
201 | None, | ||
202 | )) | ||
203 | }, | ||
204 | _ => None, | ||
205 | } | ||
206 | } | ||
202 | } | 207 | } |
203 | 208 | ||
204 | #[cfg(test)] | 209 | #[cfg(test)] |
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 200b57679..24b161c5c 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs | |||
@@ -3,12 +3,9 @@ | |||
3 | use hir::{Adt, HasSource, HirDisplay}; | 3 | use hir::{Adt, HasSource, HirDisplay}; |
4 | use ra_db::SourceDatabase; | 4 | use ra_db::SourceDatabase; |
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | algo::{ | 6 | algo::{ancestors_at_offset, find_covering_element, find_node_at_offset}, |
7 | ancestors_at_offset, find_covering_element, find_node_at_offset, | ||
8 | visit::{visitor, Visitor}, | ||
9 | }, | ||
10 | ast::{self, DocCommentsOwner}, | 7 | ast::{self, DocCommentsOwner}, |
11 | AstNode, | 8 | match_ast, AstNode, |
12 | }; | 9 | }; |
13 | 10 | ||
14 | use crate::{ | 11 | use crate::{ |
@@ -178,37 +175,45 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
178 | } | 175 | } |
179 | } else if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) { | 176 | } else if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) { |
180 | if let Some(parent) = name.syntax().parent() { | 177 | if let Some(parent) = name.syntax().parent() { |
181 | let text = visitor() | 178 | let text = match_ast! { |
182 | .visit(|node: ast::StructDef| { | 179 | match parent { |
183 | hover_text(node.doc_comment_text(), node.short_label()) | 180 | ast::StructDef(it) => { |
184 | }) | 181 | hover_text(it.doc_comment_text(), it.short_label()) |
185 | .visit(|node: ast::EnumDef| hover_text(node.doc_comment_text(), node.short_label())) | 182 | }, |
186 | .visit(|node: ast::EnumVariant| { | 183 | ast::EnumDef(it) => { |
187 | hover_text(node.doc_comment_text(), node.short_label()) | 184 | hover_text(it.doc_comment_text(), it.short_label()) |
188 | }) | 185 | }, |
189 | .visit(|node: ast::FnDef| hover_text(node.doc_comment_text(), node.short_label())) | 186 | ast::EnumVariant(it) => { |
190 | .visit(|node: ast::TypeAliasDef| { | 187 | hover_text(it.doc_comment_text(), it.short_label()) |
191 | hover_text(node.doc_comment_text(), node.short_label()) | 188 | }, |
192 | }) | 189 | ast::FnDef(it) => { |
193 | .visit(|node: ast::ConstDef| { | 190 | hover_text(it.doc_comment_text(), it.short_label()) |
194 | hover_text(node.doc_comment_text(), node.short_label()) | 191 | }, |
195 | }) | 192 | ast::TypeAliasDef(it) => { |
196 | .visit(|node: ast::StaticDef| { | 193 | hover_text(it.doc_comment_text(), it.short_label()) |
197 | hover_text(node.doc_comment_text(), node.short_label()) | 194 | }, |
198 | }) | 195 | ast::ConstDef(it) => { |
199 | .visit(|node: ast::TraitDef| { | 196 | hover_text(it.doc_comment_text(), it.short_label()) |
200 | hover_text(node.doc_comment_text(), node.short_label()) | 197 | }, |
201 | }) | 198 | ast::StaticDef(it) => { |
202 | .visit(|node: ast::RecordFieldDef| { | 199 | hover_text(it.doc_comment_text(), it.short_label()) |
203 | hover_text(node.doc_comment_text(), node.short_label()) | 200 | }, |
204 | }) | 201 | ast::TraitDef(it) => { |
205 | .visit(|node: ast::Module| hover_text(node.doc_comment_text(), node.short_label())) | 202 | hover_text(it.doc_comment_text(), it.short_label()) |
206 | .visit(|node: ast::MacroCall| hover_text(node.doc_comment_text(), None)) | 203 | }, |
207 | .accept(&parent); | 204 | ast::RecordFieldDef(it) => { |
208 | 205 | hover_text(it.doc_comment_text(), it.short_label()) | |
209 | if let Some(text) = text { | 206 | }, |
210 | res.extend(text); | 207 | ast::Module(it) => { |
211 | } | 208 | hover_text(it.doc_comment_text(), it.short_label()) |
209 | }, | ||
210 | ast::MacroCall(it) => { | ||
211 | hover_text(it.doc_comment_text(), None) | ||
212 | }, | ||
213 | _ => None, | ||
214 | } | ||
215 | }; | ||
216 | res.extend(text); | ||
212 | } | 217 | } |
213 | 218 | ||
214 | if !res.is_empty() && range.is_none() { | 219 | if !res.is_empty() && range.is_none() { |
diff --git a/crates/ra_ide_api/src/inlay_hints.rs b/crates/ra_ide_api/src/inlay_hints.rs index 9b45575f8..f1c0dc164 100644 --- a/crates/ra_ide_api/src/inlay_hints.rs +++ b/crates/ra_ide_api/src/inlay_hints.rs | |||
@@ -3,9 +3,8 @@ | |||
3 | use crate::{db::RootDatabase, FileId}; | 3 | use crate::{db::RootDatabase, FileId}; |
4 | use hir::{HirDisplay, SourceAnalyzer, Ty}; | 4 | use hir::{HirDisplay, SourceAnalyzer, Ty}; |
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | algo::visit::{visitor, Visitor}, | ||
7 | ast::{self, AstNode, TypeAscriptionOwner}, | 6 | ast::{self, AstNode, TypeAscriptionOwner}, |
8 | SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange, | 7 | match_ast, SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange, |
9 | }; | 8 | }; |
10 | 9 | ||
11 | #[derive(Debug, PartialEq, Eq)] | 10 | #[derive(Debug, PartialEq, Eq)] |
@@ -33,55 +32,58 @@ fn get_inlay_hints( | |||
33 | file_id: FileId, | 32 | file_id: FileId, |
34 | node: &SyntaxNode, | 33 | node: &SyntaxNode, |
35 | ) -> Option<Vec<InlayHint>> { | 34 | ) -> Option<Vec<InlayHint>> { |
36 | visitor() | 35 | match_ast! { |
37 | .visit(|let_statement: ast::LetStmt| { | 36 | match node { |
38 | if let_statement.ascribed_type().is_some() { | 37 | ast::LetStmt(it) => { |
39 | return None; | 38 | if it.ascribed_type().is_some() { |
40 | } | 39 | return None; |
41 | let pat = let_statement.pat()?; | 40 | } |
42 | let analyzer = SourceAnalyzer::new(db, file_id, let_statement.syntax(), None); | 41 | let pat = it.pat()?; |
43 | Some(get_pat_type_hints(db, &analyzer, pat, false)) | 42 | let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); |
44 | }) | 43 | Some(get_pat_type_hints(db, &analyzer, pat, false)) |
45 | .visit(|closure_parameter: ast::LambdaExpr| { | 44 | }, |
46 | let analyzer = SourceAnalyzer::new(db, file_id, closure_parameter.syntax(), None); | 45 | ast::LambdaExpr(it) => { |
47 | closure_parameter.param_list().map(|param_list| { | 46 | let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); |
48 | param_list | 47 | it.param_list().map(|param_list| { |
49 | .params() | 48 | param_list |
50 | .filter(|closure_param| closure_param.ascribed_type().is_none()) | 49 | .params() |
51 | .filter_map(|closure_param| closure_param.pat()) | 50 | .filter(|closure_param| closure_param.ascribed_type().is_none()) |
52 | .map(|root_pat| get_pat_type_hints(db, &analyzer, root_pat, false)) | 51 | .filter_map(|closure_param| closure_param.pat()) |
53 | .flatten() | 52 | .map(|root_pat| get_pat_type_hints(db, &analyzer, root_pat, false)) |
54 | .collect() | 53 | .flatten() |
55 | }) | 54 | .collect() |
56 | }) | 55 | }) |
57 | .visit(|for_expression: ast::ForExpr| { | 56 | }, |
58 | let pat = for_expression.pat()?; | 57 | ast::ForExpr(it) => { |
59 | let analyzer = SourceAnalyzer::new(db, file_id, for_expression.syntax(), None); | 58 | let pat = it.pat()?; |
60 | Some(get_pat_type_hints(db, &analyzer, pat, false)) | 59 | let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); |
61 | }) | 60 | Some(get_pat_type_hints(db, &analyzer, pat, false)) |
62 | .visit(|if_expr: ast::IfExpr| { | 61 | }, |
63 | let pat = if_expr.condition()?.pat()?; | 62 | ast::IfExpr(it) => { |
64 | let analyzer = SourceAnalyzer::new(db, file_id, if_expr.syntax(), None); | 63 | let pat = it.condition()?.pat()?; |
65 | Some(get_pat_type_hints(db, &analyzer, pat, true)) | 64 | let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); |
66 | }) | 65 | Some(get_pat_type_hints(db, &analyzer, pat, true)) |
67 | .visit(|while_expr: ast::WhileExpr| { | 66 | }, |
68 | let pat = while_expr.condition()?.pat()?; | 67 | ast::WhileExpr(it) => { |
69 | let analyzer = SourceAnalyzer::new(db, file_id, while_expr.syntax(), None); | 68 | let pat = it.condition()?.pat()?; |
70 | Some(get_pat_type_hints(db, &analyzer, pat, true)) | 69 | let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); |
71 | }) | 70 | Some(get_pat_type_hints(db, &analyzer, pat, true)) |
72 | .visit(|match_arm_list: ast::MatchArmList| { | 71 | }, |
73 | let analyzer = SourceAnalyzer::new(db, file_id, match_arm_list.syntax(), None); | 72 | ast::MatchArmList(it) => { |
74 | Some( | 73 | let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); |
75 | match_arm_list | 74 | Some( |
76 | .arms() | 75 | it |
77 | .map(|match_arm| match_arm.pats()) | 76 | .arms() |
78 | .flatten() | 77 | .map(|match_arm| match_arm.pats()) |
79 | .map(|root_pat| get_pat_type_hints(db, &analyzer, root_pat, true)) | 78 | .flatten() |
80 | .flatten() | 79 | .map(|root_pat| get_pat_type_hints(db, &analyzer, root_pat, true)) |
81 | .collect(), | 80 | .flatten() |
82 | ) | 81 | .collect(), |
83 | }) | 82 | ) |
84 | .accept(&node)? | 83 | }, |
84 | _ => None, | ||
85 | } | ||
86 | } | ||
85 | } | 87 | } |
86 | 88 | ||
87 | fn get_pat_type_hints( | 89 | fn get_pat_type_hints( |
diff --git a/crates/ra_ide_api/src/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs index 02cdfbc60..797e9926f 100644 --- a/crates/ra_ide_api/src/symbol_index.rs +++ b/crates/ra_ide_api/src/symbol_index.rs | |||
@@ -32,9 +32,8 @@ use ra_db::{ | |||
32 | SourceDatabase, SourceRootId, | 32 | SourceDatabase, SourceRootId, |
33 | }; | 33 | }; |
34 | use ra_syntax::{ | 34 | use ra_syntax::{ |
35 | algo::visit::{visitor, Visitor}, | ||
36 | ast::{self, NameOwner}, | 35 | ast::{self, NameOwner}, |
37 | AstNode, Parse, SmolStr, SourceFile, | 36 | match_ast, AstNode, Parse, SmolStr, SourceFile, |
38 | SyntaxKind::{self, *}, | 37 | SyntaxKind::{self, *}, |
39 | SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent, | 38 | SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent, |
40 | }; | 39 | }; |
@@ -306,16 +305,19 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> { | |||
306 | 305 | ||
307 | Some((name, ptr, name_range)) | 306 | Some((name, ptr, name_range)) |
308 | } | 307 | } |
309 | visitor() | 308 | match_ast! { |
310 | .visit(decl::<ast::FnDef>) | 309 | match node { |
311 | .visit(decl::<ast::StructDef>) | 310 | ast::FnDef(it) => { decl(it) }, |
312 | .visit(decl::<ast::EnumDef>) | 311 | ast::StructDef(it) => { decl(it) }, |
313 | .visit(decl::<ast::TraitDef>) | 312 | ast::EnumDef(it) => { decl(it) }, |
314 | .visit(decl::<ast::Module>) | 313 | ast::TraitDef(it) => { decl(it) }, |
315 | .visit(decl::<ast::TypeAliasDef>) | 314 | ast::Module(it) => { decl(it) }, |
316 | .visit(decl::<ast::ConstDef>) | 315 | ast::TypeAliasDef(it) => { decl(it) }, |
317 | .visit(decl::<ast::StaticDef>) | 316 | ast::ConstDef(it) => { decl(it) }, |
318 | .accept(node)? | 317 | ast::StaticDef(it) => { decl(it) }, |
318 | _ => None, | ||
319 | } | ||
320 | } | ||
319 | } | 321 | } |
320 | 322 | ||
321 | fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> { | 323 | fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> { |
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index edb6076bb..09230ccb2 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -295,6 +295,7 @@ fn api_walkthrough() { | |||
295 | // 1. explicitly call getter methods on AST nodes. | 295 | // 1. explicitly call getter methods on AST nodes. |
296 | // 2. use descendants and `AstNode::cast`. | 296 | // 2. use descendants and `AstNode::cast`. |
297 | // 3. use descendants and the visitor. | 297 | // 3. use descendants and the visitor. |
298 | // 4. use descendants and `match_ast!`. | ||
298 | // | 299 | // |
299 | // Here's how the first one looks like: | 300 | // Here's how the first one looks like: |
300 | let exprs_cast: Vec<String> = file | 301 | let exprs_cast: Vec<String> = file |
@@ -319,3 +320,14 @@ fn api_walkthrough() { | |||
319 | } | 320 | } |
320 | assert_eq!(exprs_cast, exprs_visit); | 321 | assert_eq!(exprs_cast, exprs_visit); |
321 | } | 322 | } |
323 | |||
324 | #[macro_export] | ||
325 | macro_rules! match_ast { | ||
326 | (match $node:ident { | ||
327 | $( ast::$ast:ident($it:ident) => $res:block, )* | ||
328 | _ => $catch_all:expr, | ||
329 | }) => {{ | ||
330 | $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* | ||
331 | { $catch_all } | ||
332 | }}; | ||
333 | } | ||
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index 4f8935b2c..ab4f15908 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs | |||
@@ -5,8 +5,7 @@ mod block; | |||
5 | use rustc_lexer::unescape; | 5 | use rustc_lexer::unescape; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | algo::visit::{visitor_ctx, VisitorCtx}, | 8 | ast, match_ast, AstNode, SyntaxError, SyntaxErrorKind, |
9 | ast, AstNode, SyntaxError, SyntaxErrorKind, | ||
10 | SyntaxKind::{BYTE, BYTE_STRING, CHAR, INT_NUMBER, STRING}, | 9 | SyntaxKind::{BYTE, BYTE_STRING, CHAR, INT_NUMBER, STRING}, |
11 | SyntaxNode, SyntaxToken, TextUnit, T, | 10 | SyntaxNode, SyntaxToken, TextUnit, T, |
12 | }; | 11 | }; |
@@ -97,12 +96,15 @@ impl From<rustc_lexer::unescape::EscapeError> for SyntaxErrorKind { | |||
97 | pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { | 96 | pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { |
98 | let mut errors = Vec::new(); | 97 | let mut errors = Vec::new(); |
99 | for node in root.descendants() { | 98 | for node in root.descendants() { |
100 | let _ = visitor_ctx(&mut errors) | 99 | match_ast! { |
101 | .visit::<ast::Literal, _>(validate_literal) | 100 | match node { |
102 | .visit::<ast::BlockExpr, _>(block::validate_block_expr) | 101 | ast::Literal(it) => { validate_literal(it, &mut errors) }, |
103 | .visit::<ast::FieldExpr, _>(|it, errors| validate_numeric_name(it.name_ref(), errors)) | 102 | ast::BlockExpr(it) => { block::validate_block_expr(it, &mut errors) }, |
104 | .visit::<ast::RecordField, _>(|it, errors| validate_numeric_name(it.name_ref(), errors)) | 103 | ast::FieldExpr(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, |
105 | .accept(&node); | 104 | ast::RecordField(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, |
105 | _ => (), | ||
106 | } | ||
107 | } | ||
106 | } | 108 | } |
107 | errors | 109 | errors |
108 | } | 110 | } |