Skip to main content

sqry_lang_cpp/relations/
queries.rs

1//! Tree-sitter queries for C++ code analysis.
2//!
3//! Provides query definitions for extracting:
4//! - Class and struct declarations (regular, templated, namespaced)
5//! - Function declarations (free functions, methods, template functions)
6//! - Call expressions (direct calls, qualified calls, member function calls)
7
8use tree_sitter::{Language, Query, QueryError};
9
10/// Compiled tree-sitter queries for Cpp constructs.
11pub struct CppQueries {
12    /// Query for class, object, and namespace declarations
13    pub classes: Query,
14    /// Query for function and property declarations
15    pub functions: Query,
16    /// Query for call expressions (function and method calls)
17    pub calls: Query,
18}
19
20impl CppQueries {
21    /// Create new `CppQueries` from the given tree-sitter language.
22    ///
23    /// # Errors
24    ///
25    /// Returns `QueryError` if any query fails to compile.
26    pub fn new(language: &Language) -> Result<Self, QueryError> {
27        Ok(Self {
28            classes: Query::new(language, CLASS_QUERY)?,
29            functions: Query::new(language, FUNCTION_QUERY)?,
30            calls: Query::new(language, CALL_QUERY)?,
31        })
32    }
33}
34
35/// Query for extracting class and struct declarations.
36///
37/// Captures:
38/// - Class specifiers: `class User { ... }`
39/// - Struct specifiers: `struct Person { ... }`
40/// - Templated classes: `template<typename T> class Container { ... }`
41/// - Templated structs: `template<typename T> struct Pair { ... }`
42///
43/// Capture groups:
44/// - `@class.name`: Class/struct type identifier
45/// - `@class`: Full `class_specifier` or `struct_specifier` node
46/// - `@template_class`: Full `template_declaration` wrapping a class
47/// - `@template_struct`: Full `template_declaration` wrapping a struct
48const CLASS_QUERY: &str = r"
49; Class specifiers: class Foo { ... };
50(class_specifier
51  name: (type_identifier) @class.name) @class
52
53; Struct specifiers: struct Foo { ... };
54(struct_specifier
55  name: (type_identifier) @class.name) @class
56
57; Class specifier inside template declaration
58(template_declaration
59  (class_specifier
60    name: (type_identifier) @class.name) @class) @template_class
61
62; Struct specifier inside template declaration
63(template_declaration
64  (struct_specifier
65    name: (type_identifier) @class.name) @class) @template_struct
66";
67
68/// Query for extracting function and method declarations.
69///
70/// Captures:
71/// - Free functions: `int calculate(int x) { ... }`
72/// - Methods: `virtual void fetchData() { ... }`
73/// - Template functions: `template<typename T> T max(T a, T b) { ... }`
74/// - Field declarations with function declarators (method signatures)
75///
76/// Capture groups:
77/// - `@func.name`: Function/method identifier
78/// - `@func`: Full `function_definition` or `field_declaration` node
79/// - `@template_func`: Full `template_declaration` wrapping a function
80const FUNCTION_QUERY: &str = r"
81; Function definitions (free functions and methods)
82(function_definition
83  declarator: (function_declarator
84    declarator: [(identifier) (field_identifier)] @func.name)) @func
85
86; Methods declared inside classes/structs without inline bodies
87(field_declaration
88  declarator: (function_declarator
89    declarator: [(field_identifier) (identifier)] @func.name)) @func
90
91; Template function declarations
92(template_declaration
93  (function_definition
94    declarator: (function_declarator
95      declarator: (identifier) @func.name)) @func) @template_func
96";
97
98/// Query for extracting call expressions.
99///
100/// Captures:
101/// - Direct calls: `printf("hello")`
102/// - Qualified calls: `std::move(x)`
103/// - Member function calls: `obj.method()`
104///
105/// Capture groups:
106/// - `@call.name`: Function name in direct or qualified `call_expression`
107/// - `@call.method`: Method name in member `call_expression`
108/// - `@call`: Full `call_expression` node
109const CALL_QUERY: &str = r"
110[
111  ; Direct function calls: foo()
112  (call_expression
113    function: (identifier) @call.name) @call
114
115  ; Qualified/scoped function calls: std::move()
116  (call_expression
117    function: (qualified_identifier) @call.name) @call
118
119  ; Member function calls: object.method()
120  (call_expression
121    function: (field_expression
122      field: [(field_identifier) (identifier)] @call.method)) @call
123]
124";
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129
130    #[test]
131    fn test_queries_compile() {
132        let language = tree_sitter_cpp::LANGUAGE.into();
133        let queries = CppQueries::new(&language);
134        assert!(queries.is_ok(), "Cpp queries should compile successfully");
135    }
136
137    #[test]
138    fn test_class_query_compiles() {
139        let language = tree_sitter_cpp::LANGUAGE.into();
140        let query = Query::new(&language, CLASS_QUERY);
141        assert!(query.is_ok(), "CLASS_QUERY should compile");
142    }
143
144    #[test]
145    fn test_function_query_compiles() {
146        let language = tree_sitter_cpp::LANGUAGE.into();
147        let query = Query::new(&language, FUNCTION_QUERY);
148        assert!(query.is_ok(), "FUNCTION_QUERY should compile");
149    }
150
151    #[test]
152    fn test_call_query_compiles() {
153        let language = tree_sitter_cpp::LANGUAGE.into();
154        let query = Query::new(&language, CALL_QUERY);
155        assert!(query.is_ok(), "CALL_QUERY should compile");
156    }
157}