gather_all_code_from_crates/
process_file.rs1crate::ix!();
2
3pub fn process_file(path: &PathBuf, criteria: &AstFilterCriteria) -> Result<String, AppError> {
4 let content = fs::read_to_string(path).map_err(|e|AppError::Io{code:e.kind()})?;
5 let parsed = ra_ap_syntax::SourceFile::parse(&content, ra_ap_syntax::Edition::CURRENT);
6 let parse_errors = parsed.errors();
7 if !parse_errors.is_empty() {
8 for err in parse_errors {
9 eprintln!("Parsing error in {}: {:?}", path.display(), err);
10 }
11 return Err(AppError::Parse { reason: ErrorReason::Parse });
12 }
13
14 let syntax = parsed.tree().syntax().clone();
15 let items = extract_items_from_ast(&syntax, *criteria.remove_doc_comments());
16
17 let mut filtered_items = items;
19
20 if !criteria.include_tests() {
22 filtered_items = filtered_items.into_iter().filter(|item| {
23 match item {
24 ItemInfo::Function(f) => !f.is_test(),
25 ItemInfo::ImplBlock { methods, .. } => {
26 let filtered: Vec<FunctionInfo> = methods.iter().filter(|m| !m.is_test()).cloned().collect();
28 filtered.len() > 0 }
30 _ => true }
32 }).map(|mut item| {
33 if let ItemInfo::ImplBlock { methods, .. } = &mut item {
34 *methods = methods.iter().filter(|m| !m.is_test()).cloned().collect();
35 }
36 item
37 }).collect();
38 }
39
40 if let Some(test_name) = criteria.single_test_name() {
42 filtered_items = filtered_items.into_iter().filter(|item| {
43 match item {
44 ItemInfo::Function(f) => *f.is_test() && f.name() == test_name,
45 ItemInfo::ImplBlock { methods, .. } => {
46 methods.iter().any(|m| *m.is_test() && m.name() == test_name)
48 }
49 _ => true
50 }
51 }).map(|mut item| {
52 if let ItemInfo::ImplBlock { methods, .. } = &mut item {
53 *methods = methods.iter().filter(|m| *m.is_test() && m.name() == test_name).cloned().collect();
54 }
55 item
56 }).collect();
57 }
58
59 if *criteria.omit_private() {
61 filtered_items = filtered_items.into_iter().filter(|item| {
62 match item {
63 ItemInfo::Function(f) => *f.is_public(),
64 ItemInfo::Struct { is_public, .. } => *is_public,
65 ItemInfo::Enum { is_public, .. } => *is_public,
66 ItemInfo::TypeAlias { is_public, .. } => *is_public,
67 ItemInfo::ImplBlock { is_public, methods, ..} => {
68 methods.iter().any(|m| *m.is_public())
70 }
71 }
72 }).map(|mut item| {
73 if let ItemInfo::ImplBlock { methods, .. } = &mut item {
74 *methods = methods.iter().filter(|m| *m.is_public()).cloned().collect();
75 }
76 item
77 }).collect();
78 }
79
80 if let Some(func_name) = criteria.single_function_name() {
82 filtered_items = filtered_items.into_iter().filter(|item| {
83 match item {
84 ItemInfo::Function(f) => f.name() == func_name,
85 ItemInfo::ImplBlock { methods, .. } => methods.iter().any(|m| m.name() == func_name),
86 _ => true
87 }
88 }).map(|mut item| {
89 if let ItemInfo::ImplBlock { methods, .. } = &mut item {
90 *methods = methods.iter().filter(|m| m.name() == func_name).cloned().collect();
91 }
92 item
93 }).collect();
94 }
95
96 let omit_bodies = *criteria.omit_bodies() && criteria.single_function_name().is_none();
97
98 let reconstructed = reconstruct_code_from_filtered_items(&filtered_items, omit_bodies);
99
100 Ok(reconstructed)
101}
102
103#[cfg(test)]
104mod process_file_tests {
105 use super::*;
106
107 #[test]
108 fn test_process_file_basic() {
109 let code = r#"
110 pub fn visible() {}
111 fn hidden() {}
112 #[test]
113 fn test_something() {}
114 "#;
115 let tmp_dir = TempDir::new().unwrap();
116 let file_path = tmp_dir.path().join("test.rs");
117 {
118 let mut f = File::create(&file_path).unwrap();
119 f.write_all(code.as_bytes()).unwrap();
120 }
121
122 let criteria = AstFilterCriteriaBuilder::default()
123 .include_tests(false)
124 .omit_private(true)
125 .build().unwrap();
126
127 let result = process_file(&file_path, &criteria).unwrap();
128 assert!(result.contains("pub fn visible()"));
132 assert!(!result.contains("test_something"));
133 assert!(!result.contains("hidden"));
134 }
135
136 #[test]
137 fn test_process_file_single_function_name() {
138 let code = r#"
139 pub fn visible() {}
140 pub fn visible2() {}
141 "#;
142 let tmp_dir = TempDir::new().unwrap();
143 let file_path = tmp_dir.path().join("test2.rs");
144 {
145 let mut f = File::create(&file_path).unwrap();
146 f.write_all(code.as_bytes()).unwrap();
147 }
148
149 let criteria = AstFilterCriteriaBuilder::default()
150 .single_function_name(Some("visible".to_string()))
151 .build().unwrap();
152
153 let result = process_file(&file_path, &criteria).unwrap();
154 assert!(result.contains("fn visible("));
155 assert!(!result.contains("visible2"));
156 }
157
158
159 #[test]
160 fn test_process_file_remove_doc_comments() {
161 let code = r#"
162 #[inline]
163 #[test]
164 fn mytest() {}
165 "#;
166 let tmp_dir = TempDir::new().unwrap();
167 let file_path = tmp_dir.path().join("test3.rs");
168 {
169 let mut f = File::create(&file_path).unwrap();
170 f.write_all(code.as_bytes()).unwrap();
171 }
172
173 let criteria = AstFilterCriteriaBuilder::default()
175 .remove_doc_comments(true)
176 .include_tests(true) .build().unwrap();
178
179 println!("criteria: {:#?}", criteria);
180
181 let result = process_file(&file_path, &criteria).unwrap();
182 println!("result: {:#?}", result);
183
184 assert!(result.contains("#[inline]"));
186 assert!(result.contains("#[test]"));
187 }
188
189 #[test]
190 fn test_process_file_syntax_error() {
191 let code = r#"
192 fn broken( {}
193 "#;
194 let tmp_dir = TempDir::new().unwrap();
195 let file_path = tmp_dir.path().join("broken.rs");
196 {
197 let mut f = File::create(&file_path).unwrap();
198 f.write_all(code.as_bytes()).unwrap();
199 }
200
201 let criteria = AstFilterCriteriaBuilder::default().build().unwrap();
202 let result = process_file(&file_path, &criteria);
203 match result {
205 Err(AppError::Parse { reason: ErrorReason::Parse }) => (),
206 _ => panic!("Expected parse error"),
207 }
208 }
209}