workspacer_consolidate/
maybe_build_function.rs1crate::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 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 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)) => { }
109 other => panic!("Expected Some(Fn), got {:?}", other),
110 }
111 }
112}