workspacer_syntax/
generate_signature_for_ast_node.rs

1// ---------------- [ File: workspacer-syntax/src/generate_signature_for_ast_node.rs ]
2crate::ix!();
3
4/// A trait to generate a textual “signature” (or declaration line(s))
5/// for different AST nodes (Fn, Struct, Enum, etc.), possibly with doc lines, etc.
6pub trait GenerateSignature: fmt::Debug + Clone {
7    /// Flexible entry point: generate signature with the given `options`.
8    fn generate_signature_with_opts(&self, opts: &SignatureOptions) -> String;
9
10    /// Default convenience wrapper: generate signature with fully expanded detail & doc lines.
11    fn generate_signature(&self) -> String {
12        let default_opts = SignatureOptions::default();
13        self.generate_signature_with_opts(&default_opts)
14    }
15}
16
17#[cfg(test)]
18mod test_generate_signature_robustness {
19    use super::*;
20
21    /// Helper: parse a snippet of code, return the first node of type T we find.
22    fn parse_first_node_of_type<T: AstNode>(code: &str) -> T {
23        let file = SourceFile::parse(code, Edition::Edition2021);
24        let syntax = file.syntax_node();
25        syntax
26            .descendants()
27            .find_map(T::cast)
28            .expect("Should parse and find a node of desired AST type.")
29    }
30
31    #[traced_test]
32    fn test_fully_expanded_fn() {
33        info!("Testing a function signature in fully expanded mode with doc lines included.");
34        let code = r#"
35            /// A doc line
36            pub fn add(a: i32, b: i32) -> i32 {
37                a + b
38            }
39        "#;
40
41        let fn_node: ast::Fn = parse_first_node_of_type(code);
42        let opts = SignatureOptionsBuilder::default()
43            .fully_expand(true)
44            .include_docs(true)
45            .build()
46            .unwrap();
47
48        let signature = fn_node.generate_signature_with_opts(&opts);
49        debug!(?signature, "Resulting signature");
50        assert!(signature.contains("/// A doc line"));
51        assert!(signature.contains("pub fn add(a: i32, b: i32) -> i32"));
52    }
53
54    #[traced_test]
55    fn test_minimal_fn() {
56        info!("Testing a function signature in minimal mode (no doc lines, placeholders).");
57        let code = r#"
58            /// Something
59            pub async fn do_stuff(x: &str) {}
60        "#;
61
62        let fn_node: ast::Fn = parse_first_node_of_type(code);
63        let opts = SignatureOptionsBuilder::default()
64            .fully_expand(false)
65            .include_docs(false)
66            .build()
67            .unwrap();
68
69        let signature = fn_node.generate_signature_with_opts(&opts);
70        debug!(?signature, "Resulting signature");
71        // We wouldn't see doc lines or expansions, but let's see if it's minimal.
72        assert!(!signature.contains("/// Something"));
73        assert!(signature.contains("pub async fn do_stuff(x: &str)")); 
74    }
75}