brokk_bifrost_cpp/
clones.rs1use brokk_bifrost_core::analyzer::tree_walk::push_children_reversed;
8use brokk_bifrost_core::clones::{
9 CloneNormalizationRules, normalize_clone_ast_label as normalize_cpp_clone_ast_label,
10 normalize_clone_leaf_token as normalize_cpp_clone_leaf_token,
11};
12use tree_sitter::{Node, Parser};
13
14const CPP_CLONE_AST_IDENTIFIER_TYPES: &[&str] = &[
15 "identifier",
16 "field_identifier",
17 "namespace_identifier",
18 "type_identifier",
19];
20const CPP_CLONE_AST_STRING_TYPES: &[&str] = &["string_literal", "raw_string_literal"];
21const CPP_CLONE_AST_NUMBER_TYPES: &[&str] = &["number_literal"];
22const CPP_CLONE_NORMALIZATION_RULES: CloneNormalizationRules = CloneNormalizationRules {
23 identifier_kinds: CPP_CLONE_AST_IDENTIFIER_TYPES,
24 string_kinds: CPP_CLONE_AST_STRING_TYPES,
25 number_kinds: CPP_CLONE_AST_NUMBER_TYPES,
26 boolean_kinds: &[],
27 boolean_values: &["true", "false"],
28 null_kinds: &[],
29 null_values: &[],
30 comment_kinds: &["comment"],
31 ignored_ast_kinds: &[],
32};
33
34pub fn cpp_clone_parser() -> Parser {
35 let mut parser = Parser::new();
36 parser
37 .set_language(&tree_sitter_cpp::LANGUAGE.into())
38 .expect("failed to load cpp parser");
39 parser
40}
41
42pub fn cpp_clone_profile(parser: &mut Parser, source: &str) -> (Vec<String>, String) {
45 let Some(tree) = parser.parse(source, None) else {
46 return (Vec::new(), String::new());
47 };
48 let mut normalized_tokens = Vec::new();
49 let mut ast_labels = Vec::new();
50 let mut stack = vec![tree.root_node()];
51 while let Some(node) = stack.pop() {
52 if cpp_is_ignorable_clone_logging_node(node, source) {
53 continue;
54 }
55 ast_labels.push(normalize_cpp_clone_ast_label(
56 node,
57 source,
58 CPP_CLONE_NORMALIZATION_RULES,
59 ));
60 if node.named_child_count() == 0 {
61 let token = normalize_cpp_clone_leaf_token(node, source, CPP_CLONE_NORMALIZATION_RULES);
62 if !token.is_empty() {
63 normalized_tokens.push(token);
64 }
65 }
66 push_children_reversed(node, &mut stack);
67 }
68 (normalized_tokens, ast_labels.join("|"))
69}
70
71fn cpp_is_ignorable_clone_logging_node(node: Node<'_>, source: &str) -> bool {
72 if node.kind() != "expression_statement" {
73 return false;
74 }
75 let text = source
76 .get(node.start_byte()..node.end_byte())
77 .unwrap_or("")
78 .trim();
79 text.contains("std::cout")
80 || text.contains("std::cerr")
81 || text.contains("std::clog")
82 || text.starts_with("printf(")
83}