workspacer_consolidate/
maybe_build_function.rs

1// ---------------- [ File: workspacer-consolidate/src/maybe_build_function.rs ]
2crate::ix!();
3
4pub fn maybe_build_function(
5    node: &SyntaxNode,
6    options: &ConsolidationOptions,
7    file_path: &PathBuf,
8    crate_path: &PathBuf,
9) -> Option<ConsolidatedItem>
10{
11    trace!("maybe_build_function called");
12    let fn_ast = ast::Fn::cast(node.clone())?;
13    if should_skip_item(node, options) {
14        trace!("Skipping fn per skip logic => returning None");
15        return None;
16    }
17
18    // Quick check for incomplete parse: e.g. param_list missing `)`
19    let param_list = fn_ast.param_list()?;
20    let ptxt = param_list.syntax().text().to_string();
21    if !ptxt.contains(')') {
22        debug!("Param list seems incomplete => returning None");
23        return None;
24    }
25
26    let raw_range = fn_ast.syntax().text_range();
27    let eff_range = compute_effective_range(fn_ast.syntax());
28
29    let docs = if *options.include_docs() {
30        extract_docs(fn_ast.syntax())
31    } else {
32        None
33    };
34    let attributes = gather_all_attrs(fn_ast.syntax());
35
36    let is_test_item = is_in_test_module(fn_ast.syntax().clone()) || has_cfg_test_attr(fn_ast.syntax());
37    let body_source = if is_test_item {
38        if *options.include_fn_bodies_in_tests() {
39            fn_ast.body().map(|b| b.syntax().text().to_string())
40        } else {
41            None
42        }
43    } else if *options.include_fn_bodies() {
44        fn_ast.body().map(|b| b.syntax().text().to_string())
45    } else {
46        None
47    };
48
49    let ci = CrateInterfaceItem::new_with_paths_and_ranges(
50        fn_ast,
51        docs,
52        attributes,
53        body_source,
54        Some(options.clone()),
55        file_path.clone(),
56        crate_path.clone(),
57        raw_range,
58        eff_range,
59    );
60    trace!("maybe_build_function returning Some(ConsolidatedItem::Fn)");
61    Some(ConsolidatedItem::Fn(ci))
62}
63
64#[cfg(test)]
65mod test_maybe_build_function {
66    use super::*;
67
68    #[traced_test]
69    fn test_none_if_not_fn() {
70        info!("Testing maybe_build_function => pass a struct => expect None");
71        let snippet = r#"struct X;"#;
72        let file = SourceFile::parse(snippet, ra_ap_syntax::Edition::Edition2021);
73        let root = file.tree().syntax().clone();
74        let node = root.descendants().find(|n| n.kind() == SyntaxKind::STRUCT).unwrap();
75        let opts = ConsolidationOptions::new();
76        let out = maybe_build_function(&node, &opts, &PathBuf::new(), &PathBuf::new());
77        assert!(out.is_none());
78    }
79
80    #[traced_test]
81    fn test_skips_if_skip_checks() {
82        info!("Testing maybe_build_function => skip logic => private test item");
83        let snippet = r#"
84            #[cfg(test)]
85            fn test_fn() {}
86        "#;
87        let file = SourceFile::parse(snippet, ra_ap_syntax::Edition::Edition2021);
88        let root = file.tree().syntax().clone();
89        let node = root.descendants().find(|n| n.kind() == SyntaxKind::FN).unwrap();
90        // no .with_test_items => skip
91        let opts = ConsolidationOptions::new();
92        let out = maybe_build_function(&node, &opts, &PathBuf::new(), &PathBuf::new());
93        assert!(out.is_none());
94    }
95
96    #[traced_test]
97    fn test_returns_fn_item() {
98        info!("Testing maybe_build_function => normal usage => returns Fn");
99        let snippet = r#"
100            fn normal() {}
101        "#;
102        let file = SourceFile::parse(snippet, ra_ap_syntax::Edition::Edition2021);
103        let root = file.tree().syntax().clone();
104        let node = root.descendants().find(|n| n.kind() == SyntaxKind::FN).unwrap();
105        let opts = ConsolidationOptions::new().with_private_items();
106        let out = maybe_build_function(&node, &opts, &PathBuf::new(), &PathBuf::new());
107        match out {
108            Some(ConsolidatedItem::Fn(_ci)) => { /* ok */ }
109            other => panic!("Expected Some(Fn), got {:?}", other),
110        }
111    }
112}