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 From 311dbb854536dd526cdbcadc6d270f9a37e4b816 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Sat, 5 Oct 2019 17:48:31 +0300 Subject: remove `visitor` module --- crates/ra_assists/src/assists/split_import.rs | 6 +- crates/ra_syntax/src/algo.rs | 2 - crates/ra_syntax/src/algo/visit.rs | 112 -------------------------- crates/ra_syntax/src/lib.rs | 43 +++++----- docs/dev/architecture.md | 4 +- docs/user/features.md | 4 +- 6 files changed, 27 insertions(+), 144 deletions(-) delete mode 100644 crates/ra_syntax/src/algo/visit.rs diff --git a/crates/ra_assists/src/assists/split_import.rs b/crates/ra_assists/src/assists/split_import.rs index 19d429daf..fe3e64af5 100644 --- a/crates/ra_assists/src/assists/split_import.rs +++ b/crates/ra_assists/src/assists/split_import.rs @@ -51,13 +51,13 @@ mod tests { fn split_import_works_with_trees() { check_assist( split_import, - "use algo:<|>:visitor::{Visitor, visit}", - "use algo::{<|>visitor::{Visitor, visit}}", + "use crate:<|>:db::{RootDatabase, FileSymbol}", + "use crate::{<|>db::{RootDatabase, FileSymbol}}", ) } #[test] fn split_import_target() { - check_assist_target(split_import, "use algo::<|>visitor::{Visitor, visit}", "::"); + check_assist_target(split_import, "use crate::<|>db::{RootDatabase, FileSymbol}", "::"); } } diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs index d55534ede..7cfea70f9 100644 --- a/crates/ra_syntax/src/algo.rs +++ b/crates/ra_syntax/src/algo.rs @@ -1,7 +1,5 @@ //! FIXME: write short doc here -pub mod visit; - use std::ops::RangeInclusive; use itertools::Itertools; diff --git a/crates/ra_syntax/src/algo/visit.rs b/crates/ra_syntax/src/algo/visit.rs deleted file mode 100644 index 4df275ba4..000000000 --- a/crates/ra_syntax/src/algo/visit.rs +++ /dev/null @@ -1,112 +0,0 @@ -//! FIXME: write short doc here - -use crate::{AstNode, SyntaxNode}; - -use std::marker::PhantomData; - -pub fn visitor<'a, T>() -> impl Visitor<'a, Output = T> { - EmptyVisitor { ph: PhantomData } -} - -pub fn visitor_ctx<'a, T, C>(ctx: C) -> impl VisitorCtx<'a, Output = T, Ctx = C> { - EmptyVisitorCtx { ph: PhantomData, ctx } -} - -pub trait Visitor<'a>: Sized { - type Output; - fn accept(self, node: &'a SyntaxNode) -> Option; - fn visit(self, f: F) -> Vis - where - N: AstNode + 'a, - F: FnOnce(N) -> Self::Output, - { - Vis { inner: self, f, ph: PhantomData } - } -} - -pub trait VisitorCtx<'a>: Sized { - type Output; - type Ctx; - fn accept(self, node: &'a SyntaxNode) -> Result; - fn visit(self, f: F) -> VisCtx - where - N: AstNode + 'a, - F: FnOnce(N, Self::Ctx) -> Self::Output, - { - VisCtx { inner: self, f, ph: PhantomData } - } -} - -#[derive(Debug)] -struct EmptyVisitor { - ph: PhantomData T>, -} - -impl<'a, T> Visitor<'a> for EmptyVisitor { - type Output = T; - - fn accept(self, _node: &'a SyntaxNode) -> Option { - None - } -} - -#[derive(Debug)] -struct EmptyVisitorCtx { - ctx: C, - ph: PhantomData T>, -} - -impl<'a, T, C> VisitorCtx<'a> for EmptyVisitorCtx { - type Output = T; - type Ctx = C; - - fn accept(self, _node: &'a SyntaxNode) -> Result { - Err(self.ctx) - } -} - -#[derive(Debug)] -pub struct Vis { - inner: V, - f: F, - ph: PhantomData, -} - -impl<'a, V, N, F> Visitor<'a> for Vis -where - V: Visitor<'a>, - N: AstNode + 'a, - F: FnOnce(N) -> >::Output, -{ - type Output = >::Output; - - fn accept(self, node: &'a SyntaxNode) -> Option { - let Vis { inner, f, .. } = self; - inner.accept(node).or_else(|| N::cast(node.clone()).map(f)) - } -} - -#[derive(Debug)] -pub struct VisCtx { - inner: V, - f: F, - ph: PhantomData, -} - -impl<'a, V, N, F> VisitorCtx<'a> for VisCtx -where - V: VisitorCtx<'a>, - N: AstNode + 'a, - F: FnOnce(N, >::Ctx) -> >::Output, -{ - type Output = >::Output; - type Ctx = >::Ctx; - - fn accept(self, node: &'a SyntaxNode) -> Result { - let VisCtx { inner, f, .. } = self; - inner.accept(node).or_else(|ctx| match N::cast(node.clone()) { - None => Err(ctx), - Some(node) => Ok(f(node, ctx)), - }) - } -} diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 09230ccb2..c315ba552 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs @@ -160,6 +160,17 @@ impl SourceFile { } } +#[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 } + }}; +} + /// This test does not assert anything and instead just shows off the crate's /// API. #[test] @@ -294,8 +305,7 @@ fn api_walkthrough() { // To recursively process the tree, there are three approaches: // 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!`. + // 3. use descendants and `match_ast!`. // // Here's how the first one looks like: let exprs_cast: Vec = file @@ -305,29 +315,18 @@ fn api_walkthrough() { .map(|expr| expr.syntax().text().to_string()) .collect(); - // An alternative is to use a visitor. The visitor does not do traversal - // automatically (so it's more akin to a generic lambda) and is constructed - // from closures. This seems more flexible than a single generated visitor - // trait. - use algo::visit::{visitor, Visitor}; + // An alternative is to use a macro. let mut exprs_visit = Vec::new(); for node in file.syntax().descendants() { - if let Some(result) = - visitor().visit::(|expr| expr.syntax().text().to_string()).accept(&node) - { - exprs_visit.push(result); + match_ast! { + match node { + ast::Expr(it) => { + let res = it.syntax().text().to_string(); + exprs_visit.push(res); + }, + _ => (), + } } } 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/docs/dev/architecture.md b/docs/dev/architecture.md index 1201f6e5a..1ffabc6ef 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md @@ -79,9 +79,7 @@ Rust syntax tree structure and parser. See - `grammar.ron` RON description of the grammar, which is used to generate `syntax_kinds` and `ast` modules, using `cargo gen-syntax` command. - `algo`: generic tree algorithms, including `walk` for O(1) stack - space tree traversal (this is cool) and `visit` for type-driven - visiting the nodes (this is double plus cool, if you understand how - `Visitor` works, you understand the design of syntax trees). + space tree traversal (this is cool). Tests for ra_syntax are mostly data-driven: `test_data/parser` contains subdirectories with a bunch of `.rs` (test vectors) and `.txt` files with corresponding syntax trees. During testing, we check diff --git a/docs/user/features.md b/docs/user/features.md index 0ce8f577b..757a02838 100644 --- a/docs/user/features.md +++ b/docs/user/features.md @@ -367,9 +367,9 @@ impl VariantData { ```rust // before: -use algo:<|>:visitor::{Visitor, visit}; +use crate:<|>:db::{RootDatabase, FileSymbol}; // after: -use algo::{<|>visitor::{Visitor, visit}}; +use crate::{<|>db::{RootDatabase, FileSymbol}}; ``` - Flip binary expression -- cgit v1.2.3