From 2fc22901730f35405d2bdfe33f88d7b3c6b14304 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Sat, 5 Oct 2019 17:03:03 +0300 Subject: replace AST visitors with macro --- .../ra_ide_api/src/completion/complete_fn_param.rs | 16 +- .../ra_ide_api/src/completion/complete_keyword.rs | 18 +- crates/ra_ide_api/src/display/navigation_target.rs | 59 ++++--- crates/ra_ide_api/src/display/structure.rs | 116 ++++++------- crates/ra_ide_api/src/goto_definition.rs | 185 +++++++++++---------- crates/ra_ide_api/src/hover.rs | 77 +++++---- crates/ra_ide_api/src/inlay_hints.rs | 104 ++++++------ crates/ra_ide_api/src/symbol_index.rs | 26 +-- crates/ra_syntax/src/lib.rs | 12 ++ 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 @@ //! FIXME: write short doc here -use ra_syntax::{ - algo::visit::{visitor_ctx, VisitorCtx}, - ast, AstNode, -}; +use ra_syntax::{ast, match_ast, AstNode}; use rustc_hash::FxHashMap; use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions}; @@ -19,10 +16,13 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) let mut params = FxHashMap::default(); for node in ctx.token.parent().ancestors() { - let _ = visitor_ctx(&mut params) - .visit::(process) - .visit::(process) - .accept(&node); + match_ast! { + match node { + ast::SourceFile(it) => { process(it, &mut params) }, + ast::ItemList(it) => { process(it, &mut params) }, + _ => (), + } + } } params .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 @@ //! FIXME: write short doc here use ra_syntax::{ - algo::visit::{visitor, Visitor}, ast::{self, LoopBodyOwner}, - AstNode, + match_ast, AstNode, SyntaxKind::*, SyntaxToken, }; @@ -84,12 +83,15 @@ fn is_in_loop_body(leaf: &SyntaxToken) -> bool { if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { break; } - let loop_body = visitor() - .visit::(|it| it.loop_body()) - .visit::(|it| it.loop_body()) - .visit::(|it| it.loop_body()) - .accept(&node); - if let Some(Some(body)) = loop_body { + let loop_body = match_ast! { + match node { + ast::ForExpr(it) => { it.loop_body() }, + ast::WhileExpr(it) => { it.loop_body() }, + ast::LoopExpr(it) => { it.loop_body() }, + _ => None, + } + }; + if let Some(body) = loop_body { if leaf.text_range().is_subrange(&body.syntax().text_range()) { return true; } 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 @@ use hir::{AssocItem, FieldSource, HasSource, ModuleSource}; use ra_db::{FileId, SourceDatabase}; use ra_syntax::{ - algo::visit::{visitor, Visitor}, ast::{self, DocCommentsOwner}, - AstNode, AstPtr, SmolStr, + match_ast, AstNode, AstPtr, SmolStr, SyntaxKind::{self, NAME}, SyntaxNode, TextRange, }; @@ -308,19 +307,22 @@ pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option let parse = db.parse(symbol.file_id); let node = symbol.ptr.to_node(parse.tree().syntax()); - visitor() - .visit(|it: ast::FnDef| it.doc_comment_text()) - .visit(|it: ast::StructDef| it.doc_comment_text()) - .visit(|it: ast::EnumDef| it.doc_comment_text()) - .visit(|it: ast::TraitDef| it.doc_comment_text()) - .visit(|it: ast::Module| it.doc_comment_text()) - .visit(|it: ast::TypeAliasDef| it.doc_comment_text()) - .visit(|it: ast::ConstDef| it.doc_comment_text()) - .visit(|it: ast::StaticDef| it.doc_comment_text()) - .visit(|it: ast::RecordFieldDef| it.doc_comment_text()) - .visit(|it: ast::EnumVariant| it.doc_comment_text()) - .visit(|it: ast::MacroCall| it.doc_comment_text()) - .accept(&node)? + match_ast! { + match node { + ast::FnDef(it) => { it.doc_comment_text() }, + ast::StructDef(it) => { it.doc_comment_text() }, + ast::EnumDef(it) => { it.doc_comment_text() }, + ast::TraitDef(it) => { it.doc_comment_text() }, + ast::Module(it) => { it.doc_comment_text() }, + ast::TypeAliasDef(it) => { it.doc_comment_text() }, + ast::ConstDef(it) => { it.doc_comment_text() }, + ast::StaticDef(it) => { it.doc_comment_text() }, + ast::RecordFieldDef(it) => { it.doc_comment_text() }, + ast::EnumVariant(it) => { it.doc_comment_text() }, + ast::MacroCall(it) => { it.doc_comment_text() }, + _ => None, + } + } } /// Get a description of a symbol. @@ -330,16 +332,19 @@ pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> let parse = db.parse(symbol.file_id); let node = symbol.ptr.to_node(parse.tree().syntax()); - visitor() - .visit(|node: ast::FnDef| node.short_label()) - .visit(|node: ast::StructDef| node.short_label()) - .visit(|node: ast::EnumDef| node.short_label()) - .visit(|node: ast::TraitDef| node.short_label()) - .visit(|node: ast::Module| node.short_label()) - .visit(|node: ast::TypeAliasDef| node.short_label()) - .visit(|node: ast::ConstDef| node.short_label()) - .visit(|node: ast::StaticDef| node.short_label()) - .visit(|node: ast::RecordFieldDef| node.short_label()) - .visit(|node: ast::EnumVariant| node.short_label()) - .accept(&node)? + match_ast! { + match node { + ast::FnDef(it) => { it.short_label() }, + ast::StructDef(it) => { it.short_label() }, + ast::EnumDef(it) => { it.short_label() }, + ast::TraitDef(it) => { it.short_label() }, + ast::Module(it) => { it.short_label() }, + ast::TypeAliasDef(it) => { it.short_label() }, + ast::ConstDef(it) => { it.short_label() }, + ast::StaticDef(it) => { it.short_label() }, + ast::RecordFieldDef(it) => { it.short_label() }, + ast::EnumVariant(it) => { it.short_label() }, + _ => None, + } + } } 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 @@ use crate::TextRange; use ra_syntax::{ - algo::visit::{visitor, Visitor}, ast::{self, AttrsOwner, NameOwner, TypeAscriptionOwner, TypeParamsOwner}, - AstNode, SourceFile, SyntaxKind, SyntaxNode, WalkEvent, + match_ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, WalkEvent, }; #[derive(Debug, Clone)] @@ -101,63 +100,66 @@ fn structure_node(node: &SyntaxNode) -> Option { }) } - visitor() - .visit(|fn_def: ast::FnDef| { - let mut detail = String::from("fn"); - if let Some(type_param_list) = fn_def.type_param_list() { - collapse_ws(type_param_list.syntax(), &mut detail); - } - if let Some(param_list) = fn_def.param_list() { - collapse_ws(param_list.syntax(), &mut detail); - } - if let Some(ret_type) = fn_def.ret_type() { - detail.push_str(" "); - collapse_ws(ret_type.syntax(), &mut detail); - } - - decl_with_detail(fn_def, Some(detail)) - }) - .visit(decl::) - .visit(decl::) - .visit(decl::) - .visit(decl::) - .visit(decl::) - .visit(|td: ast::TypeAliasDef| { - let ty = td.type_ref(); - decl_with_type_ref(td, ty) - }) - .visit(decl_with_ascription::) - .visit(decl_with_ascription::) - .visit(decl_with_ascription::) - .visit(|im: ast::ImplBlock| { - let target_type = im.target_type()?; - let target_trait = im.target_trait(); - let label = match target_trait { - None => format!("impl {}", target_type.syntax().text()), - Some(t) => { - format!("impl {} for {}", t.syntax().text(), target_type.syntax().text(),) + match_ast! { + match node { + ast::FnDef(it) => { + let mut detail = String::from("fn"); + if let Some(type_param_list) = it.type_param_list() { + collapse_ws(type_param_list.syntax(), &mut detail); + } + if let Some(param_list) = it.param_list() { + collapse_ws(param_list.syntax(), &mut detail); + } + if let Some(ret_type) = it.ret_type() { + detail.push_str(" "); + collapse_ws(ret_type.syntax(), &mut detail); } - }; - let node = StructureNode { - parent: None, - label, - navigation_range: target_type.syntax().text_range(), - node_range: im.syntax().text_range(), - kind: im.syntax().kind(), - detail: None, - deprecated: false, - }; - Some(node) - }) - .visit(|mc: ast::MacroCall| { - let first_token = mc.syntax().first_token().unwrap(); - if first_token.text().as_str() != "macro_rules" { - return None; - } - decl(mc) - }) - .accept(&node)? + decl_with_detail(it, Some(detail)) + }, + ast::StructDef(it) => { decl(it) }, + ast::EnumDef(it) => { decl(it) }, + ast::EnumVariant(it) => { decl(it) }, + ast::TraitDef(it) => { decl(it) }, + ast::Module(it) => { decl(it) }, + ast::TypeAliasDef(it) => { + let ty = it.type_ref(); + decl_with_type_ref(it, ty) + }, + ast::RecordFieldDef(it) => { decl_with_ascription(it) }, + ast::ConstDef(it) => { decl_with_ascription(it) }, + ast::StaticDef(it) => { decl_with_ascription(it) }, + ast::ImplBlock(it) => { + let target_type = it.target_type()?; + let target_trait = it.target_trait(); + let label = match target_trait { + None => format!("impl {}", target_type.syntax().text()), + Some(t) => { + format!("impl {} for {}", t.syntax().text(), target_type.syntax().text(),) + } + }; + + let node = StructureNode { + parent: None, + label, + navigation_range: target_type.syntax().text_range(), + node_range: it.syntax().text_range(), + kind: it.syntax().kind(), + detail: None, + deprecated: false, + }; + Some(node) + }, + ast::MacroCall(it) => { + let first_token = it.syntax().first_token().unwrap(); + if first_token.text().as_str() != "macro_rules" { + return None; + } + decl(it) + }, + _ => None, + } + } } #[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 @@ use ra_db::{FileId, SourceDatabase}; use ra_syntax::{ - algo::{ - find_node_at_offset, - visit::{visitor, Visitor}, - }, + algo::find_node_at_offset, ast::{self, DocCommentsOwner}, - AstNode, SyntaxNode, + match_ast, AstNode, SyntaxNode, }; use crate::{ @@ -114,91 +111,99 @@ pub(crate) fn name_definition( } fn named_target(file_id: FileId, node: &SyntaxNode) -> Option { - visitor() - .visit(|node: ast::StructDef| { - NavigationTarget::from_named( - file_id, - &node, - node.doc_comment_text(), - node.short_label(), - ) - }) - .visit(|node: ast::EnumDef| { - NavigationTarget::from_named( - file_id, - &node, - node.doc_comment_text(), - node.short_label(), - ) - }) - .visit(|node: ast::EnumVariant| { - NavigationTarget::from_named( - file_id, - &node, - node.doc_comment_text(), - node.short_label(), - ) - }) - .visit(|node: ast::FnDef| { - NavigationTarget::from_named( - file_id, - &node, - node.doc_comment_text(), - node.short_label(), - ) - }) - .visit(|node: ast::TypeAliasDef| { - NavigationTarget::from_named( - file_id, - &node, - node.doc_comment_text(), - node.short_label(), - ) - }) - .visit(|node: ast::ConstDef| { - NavigationTarget::from_named( - file_id, - &node, - node.doc_comment_text(), - node.short_label(), - ) - }) - .visit(|node: ast::StaticDef| { - NavigationTarget::from_named( - file_id, - &node, - node.doc_comment_text(), - node.short_label(), - ) - }) - .visit(|node: ast::TraitDef| { - NavigationTarget::from_named( - file_id, - &node, - node.doc_comment_text(), - node.short_label(), - ) - }) - .visit(|node: ast::RecordFieldDef| { - NavigationTarget::from_named( - file_id, - &node, - node.doc_comment_text(), - node.short_label(), - ) - }) - .visit(|node: ast::Module| { - NavigationTarget::from_named( - file_id, - &node, - node.doc_comment_text(), - node.short_label(), - ) - }) - .visit(|node: ast::MacroCall| { - NavigationTarget::from_named(file_id, &node, node.doc_comment_text(), None) - }) - .accept(node) + match_ast! { + match node { + ast::StructDef(it) => { + Some(NavigationTarget::from_named( + file_id, + &it, + it.doc_comment_text(), + it.short_label(), + )) + }, + ast::EnumDef(it) => { + Some(NavigationTarget::from_named( + file_id, + &it, + it.doc_comment_text(), + it.short_label(), + )) + }, + ast::EnumVariant(it) => { + Some(NavigationTarget::from_named( + file_id, + &it, + it.doc_comment_text(), + it.short_label(), + )) + }, + ast::FnDef(it) => { + Some(NavigationTarget::from_named( + file_id, + &it, + it.doc_comment_text(), + it.short_label(), + )) + }, + ast::TypeAliasDef(it) => { + Some(NavigationTarget::from_named( + file_id, + &it, + it.doc_comment_text(), + it.short_label(), + )) + }, + ast::ConstDef(it) => { + Some(NavigationTarget::from_named( + file_id, + &it, + it.doc_comment_text(), + it.short_label(), + )) + }, + ast::StaticDef(it) => { + Some(NavigationTarget::from_named( + file_id, + &it, + it.doc_comment_text(), + it.short_label(), + )) + }, + ast::TraitDef(it) => { + Some(NavigationTarget::from_named( + file_id, + &it, + it.doc_comment_text(), + it.short_label(), + )) + }, + ast::RecordFieldDef(it) => { + Some(NavigationTarget::from_named( + file_id, + &it, + it.doc_comment_text(), + it.short_label(), + )) + }, + ast::Module(it) => { + Some(NavigationTarget::from_named( + file_id, + &it, + it.doc_comment_text(), + it.short_label(), + )) + }, + ast::MacroCall(it) => { + Some(NavigationTarget::from_named( + file_id, + &it, + it.doc_comment_text(), + None, + )) + }, + _ => None, + } + } } #[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 @@ use hir::{Adt, HasSource, HirDisplay}; use ra_db::SourceDatabase; use ra_syntax::{ - algo::{ - ancestors_at_offset, find_covering_element, find_node_at_offset, - visit::{visitor, Visitor}, - }, + algo::{ancestors_at_offset, find_covering_element, find_node_at_offset}, ast::{self, DocCommentsOwner}, - AstNode, + match_ast, AstNode, }; use crate::{ @@ -178,37 +175,45 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option(file.syntax(), position.offset) { if let Some(parent) = name.syntax().parent() { - let text = visitor() - .visit(|node: ast::StructDef| { - hover_text(node.doc_comment_text(), node.short_label()) - }) - .visit(|node: ast::EnumDef| hover_text(node.doc_comment_text(), node.short_label())) - .visit(|node: ast::EnumVariant| { - hover_text(node.doc_comment_text(), node.short_label()) - }) - .visit(|node: ast::FnDef| hover_text(node.doc_comment_text(), node.short_label())) - .visit(|node: ast::TypeAliasDef| { - hover_text(node.doc_comment_text(), node.short_label()) - }) - .visit(|node: ast::ConstDef| { - hover_text(node.doc_comment_text(), node.short_label()) - }) - .visit(|node: ast::StaticDef| { - hover_text(node.doc_comment_text(), node.short_label()) - }) - .visit(|node: ast::TraitDef| { - hover_text(node.doc_comment_text(), node.short_label()) - }) - .visit(|node: ast::RecordFieldDef| { - hover_text(node.doc_comment_text(), node.short_label()) - }) - .visit(|node: ast::Module| hover_text(node.doc_comment_text(), node.short_label())) - .visit(|node: ast::MacroCall| hover_text(node.doc_comment_text(), None)) - .accept(&parent); - - if let Some(text) = text { - res.extend(text); - } + let text = match_ast! { + match parent { + ast::StructDef(it) => { + hover_text(it.doc_comment_text(), it.short_label()) + }, + ast::EnumDef(it) => { + hover_text(it.doc_comment_text(), it.short_label()) + }, + ast::EnumVariant(it) => { + hover_text(it.doc_comment_text(), it.short_label()) + }, + ast::FnDef(it) => { + hover_text(it.doc_comment_text(), it.short_label()) + }, + ast::TypeAliasDef(it) => { + hover_text(it.doc_comment_text(), it.short_label()) + }, + ast::ConstDef(it) => { + hover_text(it.doc_comment_text(), it.short_label()) + }, + ast::StaticDef(it) => { + hover_text(it.doc_comment_text(), it.short_label()) + }, + ast::TraitDef(it) => { + hover_text(it.doc_comment_text(), it.short_label()) + }, + ast::RecordFieldDef(it) => { + hover_text(it.doc_comment_text(), it.short_label()) + }, + ast::Module(it) => { + hover_text(it.doc_comment_text(), it.short_label()) + }, + ast::MacroCall(it) => { + hover_text(it.doc_comment_text(), None) + }, + _ => None, + } + }; + res.extend(text); } 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 @@ use crate::{db::RootDatabase, FileId}; use hir::{HirDisplay, SourceAnalyzer, Ty}; use ra_syntax::{ - algo::visit::{visitor, Visitor}, ast::{self, AstNode, TypeAscriptionOwner}, - SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange, + match_ast, SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange, }; #[derive(Debug, PartialEq, Eq)] @@ -33,55 +32,58 @@ fn get_inlay_hints( file_id: FileId, node: &SyntaxNode, ) -> Option> { - visitor() - .visit(|let_statement: ast::LetStmt| { - if let_statement.ascribed_type().is_some() { - return None; - } - let pat = let_statement.pat()?; - let analyzer = SourceAnalyzer::new(db, file_id, let_statement.syntax(), None); - Some(get_pat_type_hints(db, &analyzer, pat, false)) - }) - .visit(|closure_parameter: ast::LambdaExpr| { - let analyzer = SourceAnalyzer::new(db, file_id, closure_parameter.syntax(), None); - closure_parameter.param_list().map(|param_list| { - param_list - .params() - .filter(|closure_param| closure_param.ascribed_type().is_none()) - .filter_map(|closure_param| closure_param.pat()) - .map(|root_pat| get_pat_type_hints(db, &analyzer, root_pat, false)) - .flatten() - .collect() - }) - }) - .visit(|for_expression: ast::ForExpr| { - let pat = for_expression.pat()?; - let analyzer = SourceAnalyzer::new(db, file_id, for_expression.syntax(), None); - Some(get_pat_type_hints(db, &analyzer, pat, false)) - }) - .visit(|if_expr: ast::IfExpr| { - let pat = if_expr.condition()?.pat()?; - let analyzer = SourceAnalyzer::new(db, file_id, if_expr.syntax(), None); - Some(get_pat_type_hints(db, &analyzer, pat, true)) - }) - .visit(|while_expr: ast::WhileExpr| { - let pat = while_expr.condition()?.pat()?; - let analyzer = SourceAnalyzer::new(db, file_id, while_expr.syntax(), None); - Some(get_pat_type_hints(db, &analyzer, pat, true)) - }) - .visit(|match_arm_list: ast::MatchArmList| { - let analyzer = SourceAnalyzer::new(db, file_id, match_arm_list.syntax(), None); - Some( - match_arm_list - .arms() - .map(|match_arm| match_arm.pats()) - .flatten() - .map(|root_pat| get_pat_type_hints(db, &analyzer, root_pat, true)) - .flatten() - .collect(), - ) - }) - .accept(&node)? + match_ast! { + match node { + ast::LetStmt(it) => { + if it.ascribed_type().is_some() { + return None; + } + let pat = it.pat()?; + let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); + Some(get_pat_type_hints(db, &analyzer, pat, false)) + }, + ast::LambdaExpr(it) => { + let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); + it.param_list().map(|param_list| { + param_list + .params() + .filter(|closure_param| closure_param.ascribed_type().is_none()) + .filter_map(|closure_param| closure_param.pat()) + .map(|root_pat| get_pat_type_hints(db, &analyzer, root_pat, false)) + .flatten() + .collect() + }) + }, + ast::ForExpr(it) => { + let pat = it.pat()?; + let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); + Some(get_pat_type_hints(db, &analyzer, pat, false)) + }, + ast::IfExpr(it) => { + let pat = it.condition()?.pat()?; + let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); + Some(get_pat_type_hints(db, &analyzer, pat, true)) + }, + ast::WhileExpr(it) => { + let pat = it.condition()?.pat()?; + let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); + Some(get_pat_type_hints(db, &analyzer, pat, true)) + }, + ast::MatchArmList(it) => { + let analyzer = SourceAnalyzer::new(db, file_id, it.syntax(), None); + Some( + it + .arms() + .map(|match_arm| match_arm.pats()) + .flatten() + .map(|root_pat| get_pat_type_hints(db, &analyzer, root_pat, true)) + .flatten() + .collect(), + ) + }, + _ => None, + } + } } 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::{ SourceDatabase, SourceRootId, }; use ra_syntax::{ - algo::visit::{visitor, Visitor}, ast::{self, NameOwner}, - AstNode, Parse, SmolStr, SourceFile, + match_ast, AstNode, Parse, SmolStr, SourceFile, SyntaxKind::{self, *}, SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent, }; @@ -306,16 +305,19 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> { Some((name, ptr, name_range)) } - visitor() - .visit(decl::) - .visit(decl::) - .visit(decl::) - .visit(decl::) - .visit(decl::) - .visit(decl::) - .visit(decl::) - .visit(decl::) - .accept(node)? + match_ast! { + match node { + ast::FnDef(it) => { decl(it) }, + ast::StructDef(it) => { decl(it) }, + ast::EnumDef(it) => { decl(it) }, + ast::TraitDef(it) => { decl(it) }, + ast::Module(it) => { decl(it) }, + ast::TypeAliasDef(it) => { decl(it) }, + ast::ConstDef(it) => { decl(it) }, + ast::StaticDef(it) => { decl(it) }, + _ => None, + } + } } fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option { 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() { // 1. explicitly call getter methods on AST nodes. // 2. use descendants and `AstNode::cast`. // 3. use descendants and the visitor. + // 4. use descendants and `match_ast!`. // // Here's how the first one looks like: let exprs_cast: Vec = file @@ -319,3 +320,14 @@ fn api_walkthrough() { } assert_eq!(exprs_cast, exprs_visit); } + +#[macro_export] +macro_rules! match_ast { + (match $node:ident { + $( ast::$ast:ident($it:ident) => $res:block, )* + _ => $catch_all:expr, + }) => {{ + $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* + { $catch_all } + }}; +} 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; use rustc_lexer::unescape; use crate::{ - algo::visit::{visitor_ctx, VisitorCtx}, - ast, AstNode, SyntaxError, SyntaxErrorKind, + ast, match_ast, AstNode, SyntaxError, SyntaxErrorKind, SyntaxKind::{BYTE, BYTE_STRING, CHAR, INT_NUMBER, STRING}, SyntaxNode, SyntaxToken, TextUnit, T, }; @@ -97,12 +96,15 @@ impl From for SyntaxErrorKind { pub(crate) fn validate(root: &SyntaxNode) -> Vec { let mut errors = Vec::new(); for node in root.descendants() { - let _ = visitor_ctx(&mut errors) - .visit::(validate_literal) - .visit::(block::validate_block_expr) - .visit::(|it, errors| validate_numeric_name(it.name_ref(), errors)) - .visit::(|it, errors| validate_numeric_name(it.name_ref(), errors)) - .accept(&node); + match_ast! { + match node { + ast::Literal(it) => { validate_literal(it, &mut errors) }, + ast::BlockExpr(it) => { block::validate_block_expr(it, &mut errors) }, + ast::FieldExpr(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, + ast::RecordField(it) => { validate_numeric_name(it.name_ref(), &mut errors) }, + _ => (), + } + } } errors } -- cgit v1.2.3