From b359e4ed7f93e3b398f67a138dce8652b7558a85 Mon Sep 17 00:00:00 2001 From: Joao Duarte Date: Sat, 20 Jul 2024 11:38:54 -0300 Subject: [PATCH] feat: move identifier extraction to a trait --- .../src/java/class_like_declaration.rs | 61 ---- .../src/java/field_declaration.rs | 104 ------ .../src/java/import_declaration.rs | 79 ----- .../src/java/method_declaration.rs | 300 ------------------ matching_handlers/src/java/mod.rs | 18 +- parsing/src/identifier_extractor.rs | 52 +++ parsing/src/lib.rs | 1 + parsing/src/parse.rs | 162 +--------- parsing/src/tree_sitter_parser.rs | 47 ++- 9 files changed, 105 insertions(+), 719 deletions(-) delete mode 100644 matching_handlers/src/java/class_like_declaration.rs delete mode 100644 matching_handlers/src/java/field_declaration.rs delete mode 100644 matching_handlers/src/java/import_declaration.rs delete mode 100644 matching_handlers/src/java/method_declaration.rs create mode 100644 parsing/src/identifier_extractor.rs diff --git a/matching_handlers/src/java/class_like_declaration.rs b/matching_handlers/src/java/class_like_declaration.rs deleted file mode 100644 index 37d3fc9..0000000 --- a/matching_handlers/src/java/class_like_declaration.rs +++ /dev/null @@ -1,61 +0,0 @@ -use super::utils::find_child_of_kind; -use model::{cst_node::NonTerminal, CSTNode}; - -pub fn compute_matching_score_for_class_like_declaration<'a>( - left: &'a CSTNode, - right: &'a CSTNode, -) -> usize { - match (left, right) { - ( - CSTNode::NonTerminal(NonTerminal { - children: children_left, - .. - }), - CSTNode::NonTerminal(NonTerminal { - children: children_right, - .. - }), - ) => { - let identifier_left = - find_child_of_kind(children_left, "identifier").map(|node| node.contents()); - let identifier_right = - find_child_of_kind(children_right, "identifier").map(|node| node.contents()); - - (identifier_left.is_some() && identifier_left == identifier_right).into() - } - (_, _) => 0, - } -} - -#[cfg(test)] -mod tests { - #[test] - fn classes_with_the_same_name_match_with_score_one() { - let result = super::compute_matching_score_for_class_like_declaration( - &make_class_like_declaration("ABC"), - &make_class_like_declaration("ABC"), - ); - assert_eq!(1, result); - } - - #[test] - fn classes_of_different_names_do_not_match() { - let result = super::compute_matching_score_for_class_like_declaration( - &make_class_like_declaration("ABC"), - &make_class_like_declaration("DEF"), - ); - assert_eq!(0, result); - } - - fn make_class_like_declaration(identifier: &str) -> model::CSTNode { - model::CSTNode::NonTerminal(model::cst_node::NonTerminal { - kind: "class_declaration", - children: vec![model::CSTNode::Terminal(model::cst_node::Terminal { - kind: "identifier", - value: identifier, - ..Default::default() - })], - ..Default::default() - }) - } -} diff --git a/matching_handlers/src/java/field_declaration.rs b/matching_handlers/src/java/field_declaration.rs deleted file mode 100644 index 96686eb..0000000 --- a/matching_handlers/src/java/field_declaration.rs +++ /dev/null @@ -1,104 +0,0 @@ -use super::utils::find_identifier; -use model::{cst_node::NonTerminal, CSTNode}; - -fn find_variable_declarator<'a>(node_children: &'a [CSTNode<'a>]) -> Option<&'a NonTerminal<'a>> { - node_children - .iter() - .find(|node| node.kind() == "variable_declarator") - .and_then(|node| match node { - CSTNode::NonTerminal(non_terminal) => Some(non_terminal), - CSTNode::Terminal(_) => None, - }) -} - -pub fn compute_matching_score_for_field_declaration<'a>( - left: &'a CSTNode, - right: &'a CSTNode, -) -> usize { - match (left, right) { - ( - CSTNode::NonTerminal(NonTerminal { - children: children_left, - .. - }), - CSTNode::NonTerminal(NonTerminal { - children: children_right, - .. - }), - ) => { - // Try to find an identifier on children, and compare them - let identifier_left = find_variable_declarator(children_left) - .and_then(|node| find_identifier(&node.children)) - .map(|node| node.value); - let identifier_right = find_variable_declarator(children_right) - .and_then(|node| find_identifier(&node.children)) - .map(|node| node.value); - - (identifier_left.is_some() && identifier_left == identifier_right).into() - } - (_, _) => 0, - } -} - -#[cfg(test)] -mod tests { - use model::{ - cst_node::{NonTerminal, Terminal}, - CSTNode, - }; - - use crate::java::field_declaration::compute_matching_score_for_field_declaration; - - #[test] - fn it_returns_one_if_nodes_have_the_same_identifier() { - let left = make_field_declarator_node_with_identifier("an_identifier"); - let right = make_field_declarator_node_with_identifier("an_identifier"); - let matching_score = compute_matching_score_for_field_declaration(&left, &right); - assert_eq!(1, matching_score); - } - - #[test] - fn it_returns_zero_if_nodes_have_different_identifiers() { - let left = make_field_declarator_node_with_identifier("an_identifier_a"); - let right = make_field_declarator_node_with_identifier("an_identifier_b"); - let matching_score = compute_matching_score_for_field_declaration(&left, &right); - assert_eq!(0, matching_score); - } - - fn make_field_declarator_node_with_identifier(identifier: &str) -> CSTNode { - return CSTNode::NonTerminal(NonTerminal { - kind: "field_declaration", - children: vec![ - CSTNode::NonTerminal(NonTerminal { - kind: "modifiers", - children: vec![CSTNode::Terminal(Terminal { - kind: "private", - value: "private", - ..Default::default() - })], - ..Default::default() - }), - CSTNode::Terminal(Terminal { - kind: "type_identifier", - value: "String", - ..Default::default() - }), - CSTNode::NonTerminal(NonTerminal { - kind: "variable_declarator", - children: vec![CSTNode::Terminal(Terminal { - kind: "identifier", - value: identifier, - ..Default::default() - })], - ..Default::default() - }), - CSTNode::Terminal(Terminal { - kind: ";", - value: ";", - ..Default::default() - }), - ], - ..Default::default() - }); - } -} diff --git a/matching_handlers/src/java/import_declaration.rs b/matching_handlers/src/java/import_declaration.rs deleted file mode 100644 index 1aad2ce..0000000 --- a/matching_handlers/src/java/import_declaration.rs +++ /dev/null @@ -1,79 +0,0 @@ -use model::CSTNode; - -pub fn compute_matching_score_for_import_declaration<'a>( - left: &'a CSTNode<'a>, - right: &'a CSTNode<'a>, -) -> usize { - (left.contents() == right.contents()).into() -} - -#[cfg(test)] -mod tests { - #[test] - fn imports_of_the_same_resource_matches_with_one() { - let result = super::compute_matching_score_for_import_declaration( - &make_import_of_resource("java.util.array"), - &make_import_of_resource("java.util.array"), - ); - assert_eq!(1, result); - } - - #[test] - fn imports_of_different_resources_matches_with_zero() { - let result = super::compute_matching_score_for_import_declaration( - &make_import_of_resource("java.util.array"), - &make_import_of_resource("java.util.list"), - ); - assert_eq!(0, result); - } - - #[test] - fn imports_with_asterisks_do_match_if_they_are_equal() { - let node = model::CSTNode::NonTerminal(model::cst_node::NonTerminal { - kind: "import_declaration", - children: vec![ - model::CSTNode::Terminal(model::cst_node::Terminal { - kind: "identifier", - value: "AST", - ..Default::default() - }), - model::CSTNode::Terminal(model::cst_node::Terminal { - kind: ".", - value: ".", - ..Default::default() - }), - model::CSTNode::Terminal(model::cst_node::Terminal { - kind: "asterisk", - value: "*", - ..Default::default() - }), - ], - ..Default::default() - }); - - let result = super::compute_matching_score_for_import_declaration(&node, &node); - - assert_eq!(1, result); - } - - fn make_import_of_resource(resource: &str) -> model::CSTNode { - model::CSTNode::NonTerminal(model::cst_node::NonTerminal { - kind: "import_declaration", - children: vec![model::CSTNode::NonTerminal(model::cst_node::NonTerminal { - kind: "scoped_identifier", - children: resource - .split('.') - .map(|part| { - model::CSTNode::Terminal(model::cst_node::Terminal { - kind: "identifier", - value: part, - ..Default::default() - }) - }) - .collect(), - ..Default::default() - })], - ..Default::default() - }) - } -} diff --git a/matching_handlers/src/java/method_declaration.rs b/matching_handlers/src/java/method_declaration.rs deleted file mode 100644 index a2262d7..0000000 --- a/matching_handlers/src/java/method_declaration.rs +++ /dev/null @@ -1,300 +0,0 @@ -use super::utils::find_child_of_kind; -use model::{cst_node::NonTerminal, CSTNode}; - -pub fn compute_matching_score_for_method_declaration<'a>( - left: &'a CSTNode, - right: &'a CSTNode, -) -> usize { - match (left, right) { - ( - CSTNode::NonTerminal(NonTerminal { - children: children_left, - .. - }), - CSTNode::NonTerminal(NonTerminal { - children: children_right, - .. - }), - ) => { - // Try to find an identifier on children, and compare them - let identifier_left = - find_child_of_kind(children_left, "identifier").map(|node| node.contents()); - let identifier_right = - find_child_of_kind(children_right, "identifier").map(|node| node.contents()); - - // We also need to take method arguments into account because of overloading - let type_of_left_arguments = find_child_of_kind(children_left, "formal_parameters") - .map(|node| extract_argument_types_from_formal_parameters(node)); - let type_of_right_arguments = find_child_of_kind(children_right, "formal_parameters") - .map(|node| extract_argument_types_from_formal_parameters(node)); - - let identifiers_are_equal = - identifier_left.is_some() && identifier_left == identifier_right; - let arguments_are_equal = type_of_left_arguments.is_some() - && type_of_left_arguments == type_of_right_arguments; - - (identifiers_are_equal && arguments_are_equal).into() - } - (_, _) => 0, - } -} - -fn extract_argument_types_from_formal_parameters(node: &CSTNode) -> Vec { - match node { - CSTNode::Terminal(_) => vec![], - CSTNode::NonTerminal(non_terminal) => non_terminal - .children - .iter() - .filter(|inner_node| { - inner_node.kind() == "formal_parameter" || inner_node.kind() == "spread_parameter" - }) - .filter_map(|inner_node| match inner_node { - CSTNode::Terminal(_) => None, - CSTNode::NonTerminal(non_terminal) => Some( - non_terminal - .children - .iter() - .filter(|node| node.kind() != "modifiers" && node.kind() != "identifier") - .fold(String::new(), |acc, cur| { - format!("{} {}", acc, cur.contents()) - }), - ), - }) - .collect(), - } -} - -#[cfg(test)] -mod tests { - use model::{ - cst_node::{NonTerminal, Terminal}, - CSTNode, - }; - - use crate::java::method_declaration::compute_matching_score_for_method_declaration; - - #[test] - fn it_returns_one_if_methods_have_the_same_identifier() { - let left = - make_method_declaration_node("an_identifier", make_method_parameter("String", "name")); - let right = - make_method_declaration_node("an_identifier", make_method_parameter("String", "name")); - let matching_score = compute_matching_score_for_method_declaration(&left, &right); - assert_eq!(1, matching_score); - } - - #[test] - fn it_returns_zero_if_methods_have_different_identifiers() { - let left = make_method_declaration_node( - "an_identifier_a", - make_method_parameter("String", "name"), - ); - let right = make_method_declaration_node( - "an_identifier_b", - make_method_parameter("String", "name"), - ); - let matching_score = compute_matching_score_for_method_declaration(&left, &right); - assert_eq!(0, matching_score); - } - - #[test] - fn it_returns_one_if_methods_have_equal_identifiers_and_equal_parameters_list() { - let left = - make_method_declaration_node("an_identifier", make_method_parameter("String", "name")); - let right = make_method_declaration_node( - "an_identifier", - make_method_parameter("String", "another_name"), - ); - let matching_score = compute_matching_score_for_method_declaration(&left, &right); - assert_eq!(1, matching_score); - } - - #[test] - fn it_returns_zero_if_methods_have_equal_identifiers_but_different_parameters_list() { - let parameter_left = make_method_parameter("String", "name"); - let parameter_right = make_method_parameter("int", "another_name"); - - let left = make_method_declaration_node("an_identifier", parameter_left); - let right = make_method_declaration_node("an_identifier", parameter_right); - let matching_score = compute_matching_score_for_method_declaration(&left, &right); - assert_eq!(0, matching_score); - } - - #[test] - fn for_matching_formal_parameters_it_takes_into_consideration_all_children_except_identifier() { - let node_a = make_method_declaration_node( - "ASTNodeArtifact", - CSTNode::NonTerminal(NonTerminal { - kind: "formal_parameter", - children: vec![ - CSTNode::NonTerminal(NonTerminal { - kind: "modifiers", - children: vec![CSTNode::Terminal(Terminal { - kind: "final", - value: "final", - ..Default::default() - })], - ..Default::default() - }), - CSTNode::NonTerminal(NonTerminal { - kind: "generic_type", - children: vec![ - CSTNode::Terminal(Terminal { - kind: "type_identifier", - value: "ASTNode", - ..Default::default() - }), - CSTNode::NonTerminal(NonTerminal { - kind: "type_arguments", - children: vec![ - CSTNode::Terminal(Terminal { - kind: "<", - value: "<", - ..Default::default() - }), - CSTNode::NonTerminal(NonTerminal { - kind: "wildcard", - children: vec![CSTNode::Terminal(Terminal { - kind: "?", - value: "?", - ..Default::default() - })], - ..Default::default() - }), - CSTNode::Terminal(Terminal { - kind: ">", - value: ">", - ..Default::default() - }), - ], - ..Default::default() - }), - ], - ..Default::default() - }), - CSTNode::Terminal(Terminal { - kind: "identifier", - value: "astnode", - ..Default::default() - }), - ], - ..Default::default() - }), - ); - - let node_b = make_method_declaration_node( - "ASTNodeArtifact", - CSTNode::NonTerminal(NonTerminal { - kind: "formal_parameter", - children: vec![ - CSTNode::NonTerminal(NonTerminal { - kind: "modifiers", - children: vec![CSTNode::Terminal(Terminal { - kind: "final", - value: "final", - ..Default::default() - })], - ..Default::default() - }), - CSTNode::Terminal(Terminal { - kind: "type_identifier", - value: "FileArtifact", - ..Default::default() - }), - CSTNode::Terminal(Terminal { - kind: "identifier", - value: "astnode", - ..Default::default() - }), - ], - ..Default::default() - }), - ); - - let result = compute_matching_score_for_method_declaration(&node_a, &node_b); - assert_eq!(0, result); - } - - fn make_method_declaration_node<'a>( - identifier: &'a str, - parameter: CSTNode<'a>, - ) -> CSTNode<'a> { - CSTNode::NonTerminal(NonTerminal { - kind: "method_declaration", - children: vec![ - CSTNode::NonTerminal(NonTerminal { - kind: "modifiers", - children: vec![CSTNode::Terminal(Terminal { - kind: "public", - value: "public", - ..Default::default() - })], - ..Default::default() - }), - CSTNode::Terminal(Terminal { - kind: "void_type", - value: "void", - ..Default::default() - }), - CSTNode::Terminal(Terminal { - kind: "identifier", - value: identifier, - ..Default::default() - }), - CSTNode::NonTerminal(NonTerminal { - kind: "formal_parameters", - children: vec![ - CSTNode::Terminal(Terminal { - kind: "(", - value: "(", - ..Default::default() - }), - parameter, - CSTNode::Terminal(Terminal { - kind: ")", - value: ")", - ..Default::default() - }), - ], - ..Default::default() - }), - CSTNode::NonTerminal(NonTerminal { - kind: "block", - children: vec![ - CSTNode::Terminal(Terminal { - kind: "{", - value: "{", - ..Default::default() - }), - CSTNode::Terminal(Terminal { - kind: "}", - value: "}", - ..Default::default() - }), - ], - ..Default::default() - }), - ], - ..Default::default() - }) - } - - fn make_method_parameter<'a>(a_type: &'a str, identifier: &'a str) -> CSTNode<'a> { - CSTNode::NonTerminal(NonTerminal { - kind: "formal_parameter", - children: vec![ - CSTNode::Terminal(Terminal { - kind: "type_identifier", - value: a_type, - ..Default::default() - }), - CSTNode::Terminal(Terminal { - kind: "identifier", - value: identifier, - ..Default::default() - }), - ], - ..Default::default() - }) - } -} diff --git a/matching_handlers/src/java/mod.rs b/matching_handlers/src/java/mod.rs index 05e94f0..7be3d98 100644 --- a/matching_handlers/src/java/mod.rs +++ b/matching_handlers/src/java/mod.rs @@ -1,24 +1,8 @@ -mod class_like_declaration; -mod field_declaration; -mod import_declaration; -mod method_declaration; mod utils; use crate::MatchingHandlers; -use self::{ - class_like_declaration::compute_matching_score_for_class_like_declaration, - field_declaration::compute_matching_score_for_field_declaration, - import_declaration::compute_matching_score_for_import_declaration, - method_declaration::compute_matching_score_for_method_declaration, -}; - pub fn get_default_java_matching_handlers<'a>() -> MatchingHandlers<'a> { - let mut matching_handlers: MatchingHandlers<'a> = MatchingHandlers::new(); - - matching_handlers.register( - "constructor_declaration", - compute_matching_score_for_method_declaration, - ); + let matching_handlers: MatchingHandlers<'a> = MatchingHandlers::new(); matching_handlers } diff --git a/parsing/src/identifier_extractor.rs b/parsing/src/identifier_extractor.rs new file mode 100644 index 0000000..c6522ad --- /dev/null +++ b/parsing/src/identifier_extractor.rs @@ -0,0 +1,52 @@ +use tree_sitter::{Node, Query, QueryCursor}; + +pub trait IdentifierExtractor { + fn extract_identifier_from_node<'a>(&self, node: Node, src: &'a str) -> Option>; +} + +pub struct RegularExpressionIdentifierExtractor(&'static str); + +impl RegularExpressionIdentifierExtractor { + pub fn new(regex: &'static str) -> Self { + Self(regex) + } +} + +impl IdentifierExtractor for RegularExpressionIdentifierExtractor { + fn extract_identifier_from_node<'a>(&self, node: Node, src: &'a str) -> Option> { + let identifier = regex::Regex::new(self.0) + .unwrap() + .find(node.utf8_text(src.as_bytes()).ok()?) + .map(|m| m.as_str())?; + Some(vec![identifier]) + } +} + +pub struct TreeSitterQueryIdentifierExtractor(&'static str); + +impl TreeSitterQueryIdentifierExtractor { + pub fn new(query: &'static str) -> Self { + Self(query) + } +} + +impl IdentifierExtractor for TreeSitterQueryIdentifierExtractor { + fn extract_identifier_from_node<'a>(&self, node: Node, src: &'a str) -> Option> { + let query = Query::new(node.language(), self.0).ok()?; + let mut cursor = QueryCursor::new(); + let identifier = cursor + .matches(&query, node, src.as_bytes()) + .flat_map(|a_match| { + a_match + .captures + .iter() + .filter(|capture| { + capture.node.start_byte() >= node.start_byte() + && capture.node.end_byte() <= node.end_byte() + }) + .filter_map(|capture_index| capture_index.node.utf8_text(src.as_bytes()).ok()) + }) + .collect(); + Some(identifier) + } +} diff --git a/parsing/src/lib.rs b/parsing/src/lib.rs index 41818ba..f81730d 100644 --- a/parsing/src/lib.rs +++ b/parsing/src/lib.rs @@ -1,3 +1,4 @@ +mod identifier_extractor; mod parse; mod tree_sitter_parser; diff --git a/parsing/src/parse.rs b/parsing/src/parse.rs index b1241dc..57270e0 100644 --- a/parsing/src/parse.rs +++ b/parsing/src/parse.rs @@ -1,164 +1,9 @@ -use std::collections::HashMap; - use crate::tree_sitter_parser::ParserConfiguration; use model::{ cst_node::{NonTerminal, Terminal}, CSTNode, Point, }; -use tree_sitter::{Node, Query, QueryCursor}; - -enum IdentifierExtractor { - RegularExpression(&'static str), - TreeSitterQuery(&'static str), -} - -fn extract_identifier_from_node<'a>( - node: Node, - src: &'a str, - config: &'a ParserConfiguration, -) -> Option> { - let queries = HashMap::from([ - ( - "constructor_declaration", - IdentifierExtractor::TreeSitterQuery( - r#" - ( - constructor_declaration - name: - ( - identifier - ) - @method_name - [parameters: - ( - formal_parameters [ - ( - formal_parameter - type: - ( - _ - ) - @argument_type - ) - ( - spread_parameter (type_identifier) @spread_parameter "..." @spread_indicator - ) - ] - ) - _ - ] -) - - - "#, - ), - ), - ( - "method_declaration", - IdentifierExtractor::TreeSitterQuery( - r#" - ( - method_declaration - name: - ( - identifier - ) - @method_name - [parameters: - ( - formal_parameters [ - ( - formal_parameter - type: - ( - _ - ) - @argument_type - ) - ( - spread_parameter (type_identifier) @spread_parameter "..." @spread_indicator - ) - ] - ) - _ - ] -) - - - "#, - ), - ), - ( - "field_declaration", - IdentifierExtractor::TreeSitterQuery(r#"(variable_declarator name: _ @name)"#), - ), - ( - "import_declaration", - IdentifierExtractor::TreeSitterQuery( - r#"(import_declaration ( scoped_identifier ) @namespace)"#, - ), - ), - ( - "class_declaration", - IdentifierExtractor::RegularExpression( - r#"class [A-Za-z_][A-Za-z0-9_]*"#, - ), - ), - ( - "enum_declaration", - IdentifierExtractor::RegularExpression( - r#"enum [A-Za-z_][A-Za-z0-9_]*"#, - ), - ), - ( - "interface_declaration", - IdentifierExtractor::RegularExpression( - r#"interface [A-Za-z_][A-Za-z0-9_]*"#, - ), - ), - ]); - - let identifier_extractor = queries.get(node.kind())?; - - let identifier = match identifier_extractor { - IdentifierExtractor::RegularExpression(regex) => { - let identifier = regex::Regex::new(regex) - .unwrap() - .find(node.utf8_text(src.as_bytes()).ok()?) - .map(|m| m.as_str())?; - Some(vec![identifier]) - } - IdentifierExtractor::TreeSitterQuery(query_string) => { - let query = Query::new(config.language, query_string).ok()?; - let mut cursor = QueryCursor::new(); - let identifier = cursor - .matches(&query, node, src.as_bytes()) - .into_iter() - .flat_map(|a_match| { - a_match - .captures - .iter() - .filter(|capture| { - capture.node.start_byte() >= node.start_byte() - && capture.node.end_byte() <= node.end_byte() - }) - .filter_map(|capture_index| { - capture_index.node.utf8_text(src.as_bytes()).ok() - }) - }) - .collect(); - Some(identifier) - } - }; - - log::debug!( - "Found {:?} as identifier for node {:?}", - identifier, - node.utf8_text(src.as_bytes()).ok()? - ); - - identifier -} +use tree_sitter::Node; fn explore_node<'a>(node: Node, src: &'a str, config: &'a ParserConfiguration) -> CSTNode<'a> { if node.child_count() == 0 || config.stop_compilation_at.contains(node.kind()) { @@ -194,7 +39,10 @@ fn explore_node<'a>(node: Node, src: &'a str, config: &'a ParserConfiguration) - .map(|child| explore_node(child, src, config)) .collect(), are_children_unordered: config.kinds_with_unordered_children.contains(node.kind()), - identifier: extract_identifier_from_node(node, &src, &config), + identifier: config + .identifier_extractors + .get(node.kind()) + .and_then(|extractor| extractor.extract_identifier_from_node(node, src)), }) } } diff --git a/parsing/src/tree_sitter_parser.rs b/parsing/src/tree_sitter_parser.rs index 0e8b6ae..c20f0a4 100644 --- a/parsing/src/tree_sitter_parser.rs +++ b/parsing/src/tree_sitter_parser.rs @@ -1,6 +1,10 @@ use model::Language; use parsing_handlers::ParsingHandlers; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; + +use crate::identifier_extractor::{ + IdentifierExtractor, RegularExpressionIdentifierExtractor, TreeSitterQueryIdentifierExtractor, +}; pub struct ParserConfiguration { pub(crate) language: tree_sitter::Language, @@ -8,6 +12,7 @@ pub struct ParserConfiguration { pub(crate) kinds_with_unordered_children: HashSet<&'static str>, pub(crate) block_end_delimiters: HashSet<&'static str>, pub(crate) handlers: ParsingHandlers, + pub(crate) identifier_extractors: HashMap<&'static str, Box>, } impl From for ParserConfiguration { @@ -24,6 +29,46 @@ impl From for ParserConfiguration { .into(), block_end_delimiters: ["}"].into(), handlers: ParsingHandlers::from(Language::Java), + identifier_extractors: { + let mut map: HashMap<&'static str, Box> = + HashMap::new(); + map.insert("constructor_declaration", Box::new(TreeSitterQueryIdentifierExtractor::new(r#"(constructor_declaration name: (identifier) @method_name [parameters: (formal_parameters [ (formal_parameter type: (_) @argument_type) (spread_parameter (type_identifier) @spread_parameter "..." @spread_indicator) ]) _ ])"#))); + map.insert("method_declaration", Box::new(TreeSitterQueryIdentifierExtractor::new(r#"(method_declaration name: (identifier) @method_name [parameters: (formal_parameters [ (formal_parameter type: (_) @argument_type) (spread_parameter (type_identifier) @spread_parameter "..." @spread_indicator) ]) _ ])"#))); + map.insert( + "field_declaration", + Box::new(TreeSitterQueryIdentifierExtractor::new( + r#"(variable_declarator name: _ @name)"#, + )), + ); + map.insert( + "import_declaration", + Box::new(TreeSitterQueryIdentifierExtractor::new( + r#"(import_declaration ( scoped_identifier ) @namespace)"#, + )), + ); + + map.insert( + "class_declaration", + Box::new(RegularExpressionIdentifierExtractor::new( + r#"class [A-Za-z_][A-Za-z0-9_]*"#, + )), + ); + + map.insert( + "enum_declaration", + Box::new(RegularExpressionIdentifierExtractor::new( + r#"enum [A-Za-z_][A-Za-z0-9_]*"#, + )), + ); + + map.insert( + "interface_declaration", + Box::new(RegularExpressionIdentifierExtractor::new( + r#"interface [A-Za-z_][A-Za-z0-9_]*"#, + )), + ); + map + }, }, } }